headers = responseHeaders(true);
138 | headers.add(header+": "+value);
139 | logCallback.verbose("Response Header " + header+": "+value + " added");
140 | }
141 |
142 | public byte[] getResponseBody() {
143 | if (responseBody == null) {
144 | byte[] responseBytes = responseBytes();
145 | IResponseInfo ri = response();
146 | responseBody = new byte[responseBytes.length - ri.getBodyOffset()];
147 | System.arraycopy(responseBytes, ri.getBodyOffset(), responseBody, 0, responseBody.length);
148 | }
149 | return responseBody;
150 | }
151 |
152 | public String getResponseBodyAsString(String encoding) {
153 | return decodeBody(getResponseBody(), encoding, ()->getResponseHeader("Content-Type"));
154 | }
155 |
156 | public Object getResponseBodyAsJson(String encoding) throws JsonParser.ParseException {
157 | String value = getResponseBodyAsString(encoding);
158 | JsonParser jsonParser = new JsonParser(context.getCx(), context.getScope());
159 | return jsonParser.parseValue(value);
160 | }
161 |
162 | public void setResponseBody(byte[] responseBody) {
163 | this.responseBody = responseBody;
164 | responseBodyModified = true;
165 | }
166 |
167 | public void setResponseBodyAsString(String body) {
168 | setResponseBody(body.getBytes());
169 | }
170 |
171 | public void setResponseBodyAsJson(Object json) {
172 | Object jsonStringify = NativeJSON.stringify(context.getCx(), context.getScope(), json, null, null);
173 | setResponseBodyAsString((String)Context.jsToJava(jsonStringify,String.class));
174 | }
175 |
176 | public void setResponseAsFile(String fileName) throws IOException {
177 | commit();
178 | byte[] content = Files.readAllBytes(Paths.get(fileName));
179 | requestResponse().setResponse(content);
180 | }
181 |
182 |
183 | private boolean isModified() {
184 | return responseBodyModified || (responseHeaders != null && !responseHeaders.equals(initialResponseHeader));
185 | }
186 |
187 |
188 | public void commit() {
189 | super.commit();
190 | if (isModified()) {
191 | requestResponse().setResponse(helpers().buildHttpMessage(responseHeaders(false), getResponseBody()));
192 | this.response = null;
193 | this.responseBytes = null;
194 | this.initialResponseHeader = null;
195 | this.responseHeaders = null;
196 | this.responseBody = null;
197 | this.responseBodyModified = false;
198 | logCallback.verbose("Response updated");
199 | }
200 | }
201 |
202 | }
203 |
--------------------------------------------------------------------------------
/src/main/java/fr/safepic/burp/script/ui/component/ClickableTabIcon.java:
--------------------------------------------------------------------------------
1 | package fr.safepic.burp.script.ui.component;
2 |
3 | import javax.swing.*;
4 | import java.awt.*;
5 |
6 | public abstract class ClickableTabIcon implements Icon {
7 |
8 | private int xPos;
9 | private int yPos;
10 | private int width = 16;
11 | private int height = 16;
12 | private final static int offsetFrame = 2;
13 | protected Icon extraIcon = null;
14 | protected int frameTop;
15 | protected int frameBottom;
16 | protected int frameLeft;
17 | protected int frameRight;
18 |
19 | protected ClickableTabIcon() {
20 |
21 | }
22 |
23 | protected ClickableTabIcon(Icon extraIcon) {
24 | this.extraIcon =extraIcon;
25 | }
26 |
27 | public Color preparePaint(Graphics graphics, int x, int y) {
28 | setXYPos(x, y);
29 |
30 | Color col = graphics.getColor();
31 |
32 | graphics.setColor(Color.black);
33 |
34 | // top line of rectangle-frame...
35 | graphics.drawLine(frameLeft + 2, frameTop, frameRight - 2, frameTop);
36 | // bottom line of rectangle-frame...
37 | graphics.drawLine(frameLeft + 2, frameBottom, frameRight - 2, frameBottom);
38 | // left line of rectangle-frame...
39 | graphics.drawLine(frameLeft, frameTop + 2, frameLeft, frameBottom - 2);
40 | // right line of rectangle-frame...
41 | graphics.drawLine(frameRight, frameTop + 2, frameRight, frameBottom - 2);
42 |
43 | // rounding
44 | graphics.drawLine(frameLeft + 1, frameTop + 1, frameLeft + 1, frameTop + 1);
45 | graphics.drawLine(frameRight - 1, frameTop + 1, frameRight - 1, frameTop + 1);
46 | graphics.drawLine(frameLeft + 1, frameBottom - 1, frameLeft + 1, frameBottom - 1);
47 | graphics.drawLine(frameRight - 1, frameBottom - 1, frameRight - 1, frameBottom - 1);
48 | return col;
49 | }
50 |
51 | public int getIconWidth() {
52 | return getWidth() + (extraIcon != null ? extraIcon.getIconWidth() : 0);
53 | }
54 |
55 | public int getIconHeight() {
56 | return getHeight();
57 | }
58 |
59 | /**
60 | * Returns the x-coordinate of the position of this icon.
61 | *
62 | * @return the x-coordinate of the position of this icon.
63 | */
64 | public int getXPos() {
65 | return xPos;
66 | }
67 |
68 | /**
69 | * Returns the y-coordinate of the position of this icon.
70 | *
71 | * @return the y-coordinate of the position of this icon.
72 | */
73 | public int getYPos() {
74 | return yPos;
75 | }
76 |
77 | /**
78 | * Returns the width of this icon.
79 | *
80 | * @return the width of this icon.
81 | */
82 | public int getWidth() {
83 | return width;
84 | }
85 |
86 | /**
87 | * Returns the height of this icon.
88 | *
89 | * @return the height of this icon.
90 | */
91 | public int getHeight() {
92 | return height;
93 | }
94 |
95 | /**
96 | * Returns the extra-icon, which is to be displayed next to this icon. Might be null.
97 | *
98 | * @return the extra-icon.
99 | */
100 | public Icon getExtraIcon() {
101 | return extraIcon;
102 | }
103 |
104 | /**
105 | * Sets the x-coordinate of the position of this icon.
106 | *
107 | * @param xPos the x-coordinate of the position of this icon.
108 | */
109 | protected void setXYPos(int xPos, int yPos) {
110 | this.xPos = xPos;
111 | this.yPos = yPos;
112 | this.frameLeft = xPos + offsetFrame;
113 | this.frameRight = xPos + (width - offsetFrame);
114 | this.frameTop = yPos + offsetFrame;
115 | this.frameBottom = yPos + (height - offsetFrame);
116 |
117 | }
118 |
119 | /**
120 | * Sets the width of this icon.
121 | *
122 | * This method should be called only within the constructor-methods.
123 | *
124 | * @param width the width of this icon.
125 | */
126 | protected void setWidth(int width) {
127 | this.width = width;
128 | }
129 |
130 | /**
131 | * Sets the height of this icon.
132 | *
133 | * This method should be called only within the constructor-methods.
134 | *
135 | * @param height the height of this icon.
136 | */
137 | protected void setHeight(int height) {
138 | this.height = height;
139 | }
140 |
141 | /**
142 | * Sets the extra-icon to be displayed next to this icon.
143 | *
144 | * This method should be called only within the constructor-methods.
145 | *
146 | * @param extraIcon the extra icon to display.
147 | */
148 | protected void setExtraIcon(Icon extraIcon) {
149 | this.extraIcon = extraIcon;
150 | }
151 |
152 |
153 | public Rectangle getBounds() {
154 | return new Rectangle(getXPos(), getYPos(), getWidth(), getHeight());
155 | }
156 |
157 | }
158 |
--------------------------------------------------------------------------------
/src/main/java/fr/safepic/burp/script/ui/component/CloseTabIcon.java:
--------------------------------------------------------------------------------
1 | package fr.safepic.burp.script.ui.component;
2 |
3 | import java.awt.Color;
4 | import java.awt.Component;
5 | import java.awt.Graphics;
6 | import javax.swing.Icon;
7 |
8 | /**
9 | * Draws an icon representing an "X" in a box. The constructor accepts an icon, which will be placed next (right) to the
10 | * 'X' icon drawn by this class. If no extra icon is needed, the empty default constructor can be used, or provide
11 | * "null" as a value for the icon-object.
12 | *
13 | * @author mjoellnir
14 | * @version 1.0
15 | */
16 | public class CloseTabIcon extends ClickableTabIcon {
17 | private final static int offsetCross1 = 3;
18 | private final static int offsetCross2 = 4;
19 |
20 | /**
21 | * Creates new "X" Icon.
22 | */
23 | public CloseTabIcon() {
24 | }
25 |
26 | /**
27 | * Creates new "X" Icon with an extra icon next to it.
28 | *
29 | * @param fileIcon the Icon-object to be placed next to this icon.
30 | * @see javax.swing.Icon
31 | */
32 | public CloseTabIcon(Icon fileIcon) {
33 | super(fileIcon);
34 | }
35 |
36 | @Override
37 | public void paintIcon(Component component, Graphics graphics, int x, int y) {
38 | Color col = preparePaint(graphics, x, y);
39 |
40 | // prepare coordinates for the "X"
41 | int crossTop1 = frameTop + offsetCross1;
42 | int crossBottom1 = frameBottom - offsetCross1;
43 | int crossTop2 = frameTop + offsetCross2;
44 | int crossBottom2 = frameBottom - offsetCross2;
45 |
46 | int crossRight1 = frameRight - offsetCross1;
47 | int crossLeft1 = frameLeft + offsetCross1;
48 | int crossRight2 = frameRight - offsetCross2;
49 | int crossLeft2 = frameLeft + offsetCross2;
50 |
51 | // first diagonal of "X": top left to bottom right...
52 | graphics.drawLine(crossLeft1, crossTop1, crossRight1, crossBottom1);
53 | graphics.drawLine(crossLeft1, crossTop2, crossRight2, crossBottom1);
54 | graphics.drawLine(crossLeft2, crossTop1, crossRight1, crossBottom2);
55 |
56 | // second diagonal of "X": top right to bottom left...
57 | graphics.drawLine(crossRight1, crossTop1, crossLeft1, crossBottom1);
58 | graphics.drawLine(crossRight1, crossTop2, crossLeft2, crossBottom1);
59 | graphics.drawLine(crossRight2, crossTop1, crossLeft1, crossBottom2);
60 |
61 | graphics.setColor(col);
62 |
63 | if (extraIcon != null) {
64 | extraIcon.paintIcon(component, graphics, x + getWidth(), y + 2);
65 | }
66 | }
67 | }
--------------------------------------------------------------------------------
/src/main/java/fr/safepic/burp/script/ui/component/CloseableTabbedPane.java:
--------------------------------------------------------------------------------
1 | package fr.safepic.burp.script.ui.component;
2 |
3 | import javax.swing.*;
4 | import java.awt.*;
5 | import java.awt.event.MouseEvent;
6 | import java.awt.event.MouseListener;
7 | import java.util.Collections;
8 | import java.util.HashMap;
9 | import java.util.Map;
10 | import java.util.function.Supplier;
11 |
12 | public class CloseableTabbedPane extends JTabbedPane implements MouseListener {
13 | final Map> iconCallback = Collections.synchronizedMap(new HashMap<>());
14 | final Supplier addListener;
15 |
16 | /**
17 | * Creates a new instance of ClosableTabbedPane
18 | */
19 | public CloseableTabbedPane(String name, JPanel component, Supplier addListener) {
20 | super();
21 | this.addListener = addListener;
22 | super.addTab(name, new JScrollPane(component, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER));
23 | JPanel empty = new JPanel();
24 | iconCallback.put(empty, addListener);
25 | super.addTab("", null, empty, "Click here to create new script");
26 | initializeMouseListener();
27 | setEnabledAt(1, false);
28 | setDisabledIconAt(1, new NewTabIcon());
29 | /*addChangeListener((l)->{
30 | if (getTabCount() -1 == getSelectedIndex()) {
31 | addListener.get();
32 | }
33 | });*/
34 | }
35 |
36 | /**
37 | * Appends a tab without closing-capabilities, just as the standard JTabbedPane would do.
38 | *
39 | * @see javax.swing.JTabbedPane#addTab(String title, Component component) addTab
40 | */
41 | @Override
42 | public void addTab(String title, Component component) {
43 | this.addTab(title, null, component, null, null);
44 | }
45 |
46 | @Override
47 | public void addTab(String title, Icon icon, Component component, String tip) {
48 | this.addTab(title, icon, component, tip, null);
49 | }
50 |
51 | @Override
52 | public void addTab(String title, Icon icon, Component component) {
53 | this.addTab(title, icon, component, null, null);
54 | }
55 |
56 | /**
57 | * Appends a tab with or without closing-capabilities, depending on the flag isClosable. If isClosable is true, a
58 | * close-icon ('X') is displayed left of the title. If extraIcon is not null, it will be displayed between the closing
59 | * icon (if present) and the tab's title. The extraIcon will be displayed independently of the closing-icon.
60 | *
61 | * @param title Title of this tab.
62 | * @param component Contents of this tab.
63 | * @param extraIcon Extra icon to be displayed.
64 | * @see javax.swing.JTabbedPane#addTab(String title, Component component) addTab
65 | */
66 | public void addTab(String title, Icon extraIcon, Component component, String tip, Supplier iconCallback) {
67 | if (iconCallback != null) {
68 | this.iconCallback.put(component, iconCallback);
69 | }
70 | if (extraIcon != null) {
71 | super.insertTab(title, extraIcon, component, tip, getTabCount() - 1);
72 | } else {
73 | super.insertTab(title, null, component, null, getTabCount() - 1);
74 | }
75 | }
76 |
77 | @Override
78 | public void removeTabAt(int index) {
79 | iconCallback.remove(getComponentAt(index));
80 | super.removeTabAt(index);
81 | }
82 |
83 | @Override
84 | public void mouseClicked(MouseEvent evt) {
85 | int tabIndex = getUI().tabForCoordinate(this, evt.getX(), evt.getY());
86 | if (tabIndex < 0) {
87 | return;
88 | }
89 |
90 | Icon icon = getIconAt(tabIndex);
91 | if (icon == null) {
92 | icon = getDisabledIconAt(tabIndex);
93 | }
94 |
95 | if (!(icon instanceof ClickableTabIcon)) {
96 | // This tab is not intended to be closeable.
97 | return;
98 | }
99 |
100 | Rectangle rect = ((ClickableTabIcon) icon).getBounds();
101 | if (rect.contains(evt.getX(), evt.getY())) {
102 | //the tab is being closed
103 | Supplier listener = iconCallback.get(getComponentAt(tabIndex));
104 | if (listener!=null) {
105 | listener.get();
106 | }
107 | }
108 | }
109 |
110 | @Override
111 | public void mouseEntered(MouseEvent evt) {
112 | }
113 |
114 | @Override
115 | public void mouseExited(MouseEvent evt) {
116 | }
117 |
118 | @Override
119 | public void mousePressed(MouseEvent evt) {
120 | }
121 |
122 | @Override
123 | public void mouseReleased(MouseEvent evt) {
124 | }
125 |
126 | private void initializeMouseListener() {
127 | addMouseListener(this);
128 | }
129 | }
--------------------------------------------------------------------------------
/src/main/java/fr/safepic/burp/script/ui/component/FSJTextArea.java:
--------------------------------------------------------------------------------
1 | package fr.safepic.burp.script.ui.component;
2 |
3 | import javax.swing.*;
4 | import java.awt.*;
5 |
6 | public class FSJTextArea extends JTextArea {
7 | public FSJTextArea() {
8 | }
9 | public FSJTextArea(int rows, int columns) {
10 | super(rows, columns);
11 | }
12 |
13 | public void setFont(Font font) {
14 | super.setFont(new Font("monospaced", Font.PLAIN, 16));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/fr/safepic/burp/script/ui/component/FSRTextArea.java:
--------------------------------------------------------------------------------
1 | package fr.safepic.burp.script.ui.component;
2 |
3 | import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
4 |
5 | import java.awt.*;
6 |
7 | public class FSRTextArea extends RSyntaxTextArea {
8 | public FSRTextArea() {
9 | }
10 | public FSRTextArea(int rows, int cols) {
11 | super(rows, cols);
12 | }
13 | public void setFont(Font font) {
14 | super.setFont(new Font("monospaced", Font.PLAIN, 16));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/fr/safepic/burp/script/ui/component/MyTextArea.java:
--------------------------------------------------------------------------------
1 | package fr.safepic.burp.script.ui.component;
2 |
3 | import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
4 | import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
5 | import org.fife.ui.rtextarea.RTextScrollPane;
6 |
7 | import javax.swing.*;
8 | import javax.swing.event.DocumentEvent;
9 | import javax.swing.event.DocumentListener;
10 | import java.awt.*;
11 | import java.awt.event.ActionEvent;
12 | import java.util.*;
13 | import java.io.IOException;
14 | import java.net.URI;
15 | import java.nio.charset.StandardCharsets;
16 | import java.nio.file.*;
17 | import java.nio.file.attribute.BasicFileAttributes;
18 | import java.util.List;
19 |
20 | public class MyTextArea extends JPanel {
21 | private final RSyntaxTextArea coloredArea = new FSRTextArea(15, 80);
22 | private final JTextArea normalArea = new FSJTextArea(15, 80);
23 | private final CardLayout layout = new CardLayout();
24 | private boolean colored = true;
25 |
26 | private static class MenuEntry {
27 | JPopupMenu popup;
28 | JMenu menu;
29 |
30 | public MenuEntry(JMenu menu) {
31 | this.menu = menu;
32 | }
33 |
34 | public MenuEntry(JPopupMenu popup) {
35 | this.popup = popup;
36 | }
37 |
38 | public void add(JMenu child) {
39 | if (popup != null) {
40 | popup.add(child);
41 | } else {
42 | menu.add(child);
43 | }
44 | }
45 | public void add(JMenuItem child) {
46 | if (popup != null) {
47 | popup.add(child);
48 | } else {
49 | menu.add(child);
50 | }
51 | }
52 |
53 | }
54 |
55 | public MyTextArea(String name) {
56 | setName(name);
57 | setLayout(layout);
58 | coloredArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT);
59 | RTextScrollPane coloredAreaSP = new RTextScrollPane(coloredArea);
60 | add(coloredAreaSP, "colored");
61 | JScrollPane normalAreaSP = new JScrollPane(normalArea);
62 | add(normalAreaSP, "normal");
63 | layout.show(this, "colored");
64 |
65 | normalArea.getDocument().addDocumentListener(new ScriptDocumentListener(false));
66 | coloredArea.getDocument().addDocumentListener(new ScriptDocumentListener(true));
67 | JPopupMenu coloredAreaMenu = coloredArea.getPopupMenu();
68 | JPopupMenu normalAreaMenu = new JPopupMenu();
69 | normalArea.setComponentPopupMenu(normalAreaMenu);
70 | try {
71 | URI uri = MyTextArea.class.getResource("/sample-menu-item").toURI();
72 | if ("jar".equals(uri.getScheme())) {
73 | try {
74 | FileSystems.getFileSystem(uri);
75 | } catch( FileSystemNotFoundException e ) {
76 | Map env = new HashMap<>();
77 | env.put("create", "true");
78 | FileSystems.newFileSystem(uri, env);
79 | }
80 | }
81 | Path myPath = Paths.get(uri);
82 | Stack stack = new Stack<>();
83 |
84 | List paths = new ArrayList<>();
85 | SimpleFileVisitor visitor = new SimpleFileVisitor<>() {
86 | @Override
87 | public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
88 | if (!myPath.equals(dir)) {
89 | MenuEntry parent = stack.peek();
90 | JMenu child = new JMenu(dir.getFileName().toString());
91 | parent.add(child);
92 | stack.push(new MenuEntry(child));
93 | }
94 | return super.preVisitDirectory(dir, attrs);
95 | }
96 | @Override
97 | public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
98 | paths.add(file);
99 | return super.visitFile(file, attrs);
100 | }
101 | @Override
102 | public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
103 | return super.visitFileFailed(file, exc);
104 | }
105 | @Override
106 | public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
107 | paths.stream().sorted(Comparator.comparing(file->file.getFileName().toString()))
108 | .forEach(file->{
109 | String value = file.getFileName().toString();
110 | value = value.substring(0, value.length() - 4);
111 | stack.peek().add(new JMenuItem(new AbstractAction(value) {
112 | @Override
113 | public void actionPerformed(ActionEvent e) {
114 | insertSample(file);
115 | }
116 | }));
117 | });
118 | paths.clear();
119 | if (!myPath.equals(dir)) {
120 | stack.pop();
121 | }
122 | return super.postVisitDirectory(dir, exc);
123 | }
124 | };
125 |
126 | JMenu sample = new JMenu("Code sample");
127 | coloredAreaMenu.add(sample);
128 | stack.push(new MenuEntry(sample));
129 | Files.walkFileTree(myPath, visitor);
130 | stack.clear();
131 |
132 | stack.push(new MenuEntry(normalAreaMenu));
133 | Files.walkFileTree(myPath, visitor);
134 |
135 |
136 | /* Stream walk = Files.walk(myPath, 2);
137 | Map menus = new
138 | walk.forEach(path -> {
139 | System.out.println(myPath.relativize(path));
140 | });*/
141 | } catch (Exception ex) {
142 | ex.printStackTrace();
143 | }
144 |
145 |
146 |
147 | }
148 |
149 | public void insertSample(Path path) {
150 | try {
151 | if (colored) {
152 | coloredArea.insert(Files.readString(path, StandardCharsets.UTF_8), coloredArea.getCaretPosition());
153 | } else {
154 | normalArea.insert(Files.readString(path, StandardCharsets.UTF_8), normalArea.getCaretPosition());
155 | }
156 | }catch (Exception ex) {
157 | ex.printStackTrace();
158 | }
159 | }
160 | public void addDocumentListener(DocumentListener listener) {
161 | listenerList.add(DocumentListener.class, listener);
162 | }
163 |
164 |
165 | private class ScriptDocumentListener implements DocumentListener {
166 | private final boolean fireWhenColored;
167 | ScriptDocumentListener(boolean fireWhenColored){
168 | this.fireWhenColored = fireWhenColored;
169 | }
170 |
171 | @Override
172 | public void insertUpdate(DocumentEvent e) {
173 | if (fireWhenColored == colored) {
174 | for (DocumentListener listener : listenerList.getListeners(DocumentListener.class)) {
175 | listener.insertUpdate(e);
176 | }
177 | }
178 | }
179 |
180 | @Override
181 | public void removeUpdate(DocumentEvent e) {
182 | if (fireWhenColored == colored) {
183 | for (DocumentListener listener : listenerList.getListeners(DocumentListener.class)) {
184 | listener.removeUpdate(e);
185 | }
186 | }
187 | }
188 |
189 | @Override
190 | public void changedUpdate(DocumentEvent e) {
191 | if (fireWhenColored == colored) {
192 | for (DocumentListener listener : listenerList.getListeners(DocumentListener.class)) {
193 | listener.changedUpdate(e);
194 | }
195 | }
196 | }
197 | }
198 |
199 | public void setColored(boolean b) {
200 | String currentValue = getText();
201 | colored = b;
202 | layout.show(this, b ? "colored" : "normal");
203 | setText(currentValue);
204 | }
205 |
206 |
207 | public String getText() {
208 | return colored ? coloredArea.getText() : normalArea.getText();
209 | }
210 |
211 | public void setText(String txt) {
212 | if (colored) {
213 | coloredArea.setText(txt);
214 | } else {
215 | normalArea.setText(txt);
216 | }
217 | }
218 |
219 | }
220 |
--------------------------------------------------------------------------------
/src/main/java/fr/safepic/burp/script/ui/component/NewTabIcon.java:
--------------------------------------------------------------------------------
1 | package fr.safepic.burp.script.ui.component;
2 |
3 | import javax.swing.*;
4 | import java.awt.*;
5 |
6 | /**
7 | * Draws an icon representing an "X" in a box. The constructor accepts an icon, which will be placed next (right) to the
8 | * 'X' icon drawn by this class. If no extra icon is needed, the empty default constructor can be used, or provide
9 | * "null" as a value for the icon-object.
10 | *
11 | * @author mjoellnir
12 | * @version 1.0
13 | */
14 | public class NewTabIcon extends ClickableTabIcon {
15 | private final static int offsetCross = 2;
16 |
17 | /**
18 | * Creates new "X" Icon.
19 | */
20 | public NewTabIcon() {
21 | }
22 |
23 | /**
24 | * Creates new "X" Icon with an extra icon next to it.
25 | *
26 | * @param fileIcon the Icon-object to be placed next to this icon.
27 | * @see Icon
28 | */
29 | public NewTabIcon(Icon fileIcon) {
30 | super(fileIcon);
31 | }
32 |
33 | @Override
34 | public void paintIcon(Component component, Graphics graphics, int x, int y) {
35 | Color col = preparePaint(graphics, x, y);
36 | // prepare coordinates for the "+"
37 | int horizontalXPos1 = frameLeft + offsetCross;
38 | int horizontalXPos2 = frameRight - offsetCross;
39 | int horizontalYPos= frameTop + (frameBottom - frameTop -2) / 2;
40 |
41 | int verticalYPos1 = frameTop + offsetCross;
42 | int verticalYPos2 = frameBottom - offsetCross;
43 | int verticalXPos= frameLeft + (frameRight - frameLeft -2) / 2;
44 | int yPos = (frameRight - frameLeft - 2) / 2;
45 | int xPos = (frameBottom - frameTop - 2) / 2;
46 |
47 | // Horizontal
48 | graphics.drawLine(horizontalXPos1, horizontalYPos, horizontalXPos2, horizontalYPos);
49 | graphics.drawLine(horizontalXPos1, horizontalYPos+1, horizontalXPos2, horizontalYPos+1);
50 | graphics.drawLine(horizontalXPos1, horizontalYPos+2, horizontalXPos2, horizontalYPos+2);
51 | // Vertical
52 | graphics.drawLine(verticalXPos, verticalYPos1, verticalXPos, verticalYPos2);
53 | graphics.drawLine(verticalXPos+1, verticalYPos1, verticalXPos+1, verticalYPos2);
54 | graphics.drawLine(verticalXPos+2, verticalYPos1, verticalXPos+2, verticalYPos2);
55 |
56 | graphics.setColor(col);
57 |
58 | if (extraIcon != null) {
59 | extraIcon.paintIcon(component, graphics, x + getWidth(), y + 2);
60 | }
61 | }
62 |
63 | }
--------------------------------------------------------------------------------
/src/main/java/fr/safepic/burp/script/ui/model/ScriptRef.java:
--------------------------------------------------------------------------------
1 | package fr.safepic.burp.script.ui.model;
2 |
3 | import burp.IBurpExtenderCallbacks;
4 | import fr.safepic.burp.script.ui.panel.ScriptPanel;
5 |
6 | import java.util.Objects;
7 | import java.util.UUID;
8 | import java.util.prefs.BackingStoreException;
9 | import java.util.prefs.Preferences;
10 |
11 | public class ScriptRef {
12 | private String uid = UUID.randomUUID().toString();
13 | private boolean enabled;
14 | private volatile boolean scriptError;
15 | private boolean inScope = true;
16 | private int tools = IBurpExtenderCallbacks.TOOL_PROXY;
17 | private transient ScriptPanel panel;
18 | private String name;
19 | private String description;
20 | private boolean sessionHandling;
21 | private String scriptRequest;
22 | private String scriptResponse;
23 | private transient ScriptRef backup;
24 | private boolean savedGlobally;
25 |
26 | public ScriptRef() {
27 |
28 | }
29 |
30 | public ScriptRef getBackup() {
31 | return backup;
32 | }
33 |
34 | public ScriptRef backup() {
35 | backup = new ScriptRef();
36 | backup.enabled = enabled;
37 | backup.name = name;
38 | backup.description = description;
39 | backup.inScope = inScope;
40 | backup.tools = tools;
41 | backup.scriptRequest = scriptRequest;
42 | backup.scriptResponse = scriptResponse;
43 | backup.sessionHandling = sessionHandling;
44 | return backup;
45 | }
46 |
47 | public void restore() {
48 | enabled = backup.enabled;
49 | name = backup.name;
50 | description = backup.description;
51 | inScope = backup.inScope;
52 | tools = backup.tools;
53 | scriptRequest = backup.scriptRequest;
54 | scriptResponse = backup.scriptResponse;
55 | sessionHandling = backup.sessionHandling;
56 | backup = null;
57 | }
58 |
59 | public boolean isEnabled() {
60 | return enabled;
61 | }
62 |
63 | public void setEnabled(boolean enabled) {
64 | this.enabled = enabled;
65 | }
66 |
67 | public ScriptPanel getPanel() {
68 | return panel;
69 | }
70 |
71 | public void setPanel(ScriptPanel panel) {
72 | this.panel = panel;
73 | }
74 |
75 | public String getName() {
76 | return name;
77 | }
78 |
79 | public void setName(String name) {
80 | this.name = name;
81 | }
82 |
83 | public String getScriptRequest() {
84 | return scriptRequest;
85 | }
86 |
87 | public void setScriptRequest(String scriptRequest) {
88 | this.scriptRequest = scriptRequest;
89 | }
90 |
91 | public String getScriptResponse() {
92 | return scriptResponse;
93 | }
94 |
95 | public void setScriptResponse(String scriptResponse) {
96 | this.scriptResponse = scriptResponse;
97 | }
98 |
99 | public String getDescription() {
100 | return description;
101 | }
102 |
103 | public void setDescription(String description) {
104 | this.description = description;
105 | }
106 |
107 | public boolean isInScope() {
108 | return inScope;
109 | }
110 |
111 | public void setInScope(boolean inScope) {
112 | this.inScope = inScope;
113 | }
114 |
115 | public int getTools() {
116 | return tools;
117 | }
118 |
119 | public void setTools(int tools) {
120 | this.tools = tools;
121 | }
122 |
123 | public boolean needsSave() {
124 | if (backup == null) {
125 | return false;
126 | }
127 | if (backup.isInScope() != isInScope()) return true;
128 | if (backup.getTools() != getTools()) return true;
129 | if (!Objects.equals(backup.sessionHandling, sessionHandling)) return true;
130 | if (!Objects.equals(backup.getName(), getName())) return true;
131 | if (!Objects.equals(backup.getDescription(), getDescription())) return true;
132 | if (!Objects.equals(backup.getScriptRequest(), getScriptRequest())) return true;
133 | return !Objects.equals(backup.getScriptResponse(), getScriptResponse());
134 | }
135 |
136 |
137 |
138 | public void saveData(Preferences pref) throws BackingStoreException {
139 | Preferences node = pref.node(uid);
140 | node.putInt("version", 1);
141 | node.putBoolean("enabled", enabled);
142 | node.putBoolean("inScope", inScope);
143 | node.putInt("tools", tools);
144 | node.put("name", name);
145 | node.putBoolean("sessionHandling", sessionHandling);
146 | node.put("description", description);
147 | node.put("scriptRequest", scriptRequest);
148 | node.put("scriptResponse", scriptResponse);
149 | savedGlobally = true;
150 | node.flush();
151 | }
152 |
153 | public static ScriptRef restoreData(Preferences node) {
154 | ScriptRef ref = new ScriptRef();
155 | ref.uid = node.name();
156 | ref.enabled = node.getBoolean("enabled", false);
157 | ref.inScope = node.getBoolean("inScope", true);
158 | ref.tools = node.getInt("tools", 0);
159 | ref.name = node.get("name", node.name());
160 | ref.sessionHandling = node.getBoolean("sessionHandling", false);
161 | ref.description = node.get("description", "");
162 | ref.scriptRequest = node.get("scriptRequest", "");
163 | ref.scriptResponse = node.get("scriptResponse", "");
164 | ref.savedGlobally = true;
165 | return ref;
166 | }
167 |
168 | public String getUid() {
169 | return uid;
170 | }
171 |
172 | public boolean isSavedGlobally() {
173 | return savedGlobally;
174 | }
175 |
176 | public boolean isScriptError() {
177 | return scriptError;
178 | }
179 |
180 | public void setScriptError(boolean scriptError) {
181 | this.scriptError = scriptError;
182 | }
183 |
184 | public boolean isSessionHandling() {
185 | return sessionHandling;
186 | }
187 |
188 | public void setSessionHandling(boolean sessionHandling) {
189 | this.sessionHandling = sessionHandling;
190 | }
191 | /*
192 | private boolean local;
193 | private boolean enabled;
194 | private boolean inScope = true;
195 | private int tools = IBurpExtenderCallbacks.TOOL_PROXY;
196 | private transient Script2Panel panel;
197 | private String name;
198 | private String description;
199 | private String scriptRequest;
200 | private String scriptResponse;
201 | private transient ScriptRef backup;
202 |
203 | */
204 | }
205 |
--------------------------------------------------------------------------------
/src/main/java/fr/safepic/burp/script/ui/model/ScriptTableModel.java:
--------------------------------------------------------------------------------
1 | package fr.safepic.burp.script.ui.model;
2 |
3 | import javax.swing.*;
4 | import javax.swing.table.AbstractTableModel;
5 | import javax.swing.table.DefaultTableCellRenderer;
6 | import javax.swing.table.TableCellRenderer;
7 | import java.awt.*;
8 | import java.util.List;
9 |
10 | public class ScriptTableModel extends AbstractTableModel implements TableCellRenderer {
11 | private final DefaultTableCellRenderer DEFAULT_RENDERER = new DefaultTableCellRenderer();
12 | private volatile Color defaultBackgroundColor;
13 |
14 | private final List scripts;
15 |
16 | public ScriptTableModel(List scripts) {
17 | this.scripts =scripts;
18 | }
19 |
20 | @Override
21 | public boolean isCellEditable(int rowIndex, int columnIndex) {
22 | return columnIndex == 0;
23 | }
24 |
25 | @Override
26 | public String getColumnName(int columnIndex) {
27 | switch (columnIndex) {
28 | case 0:
29 | return "Enabled";
30 | case 1:
31 | return "Scope Only";
32 | case 2:
33 | return "Name";
34 | case 3:
35 | return "Description";
36 | case 4:
37 | return "State";
38 | default:
39 | return null;
40 | }
41 | }
42 |
43 | @Override
44 | public int getRowCount() {
45 | return scripts.size();
46 | }
47 |
48 | @Override
49 | public int getColumnCount() {
50 | return 5;
51 | }
52 |
53 | @Override
54 | public Class> getColumnClass(int columnIndex) {
55 | switch (columnIndex) {
56 | case 0:
57 | case 1:
58 | return Boolean.class;
59 | case 2:
60 | case 3:
61 | case 4:
62 | return String.class;
63 | default:
64 | return null;
65 | }
66 | }
67 |
68 | public void fireDataChanged(ScriptRef sr) {
69 | int idx = scripts.indexOf(sr);
70 | for (int i = 0; i contentQueue = new LinkedList<>();
44 | private boolean contentQueueModified = false;
45 | private final ScriptDocumentListener documentListener = new ScriptDocumentListener();
46 | private boolean updateObject=true;
47 | private final ScriptRef scriptRef;
48 |
49 | private final JScrollPane scrollPane;
50 | private final BiConsumer scriptRefChangeConsumer;
51 | private final JButton btnRevert = new JButton("Revert");
52 | private final JButton btnDelete = new JButton("Delete");
53 | private final JButton btnSave = new JButton("Save");
54 | private final JComboBox logLevel = new JComboBox<>(new String[]{"NONE", "ERROR","INFO", "DEBUG", "VERBOSE"});
55 |
56 | public enum Action {
57 | UPDATE,
58 | SAVE,
59 | DELETE
60 | }
61 |
62 | public ScriptPanel(ScriptRef scriptRef, BiConsumer scriptRefChangeConsumer) {
63 | setName(scriptRef.getName());
64 | scrollPane = new JScrollPane(this, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
65 | this.scriptRef = scriptRef;
66 | this.scriptRefChangeConsumer = scriptRefChangeConsumer;
67 | this.logLevel.setSelectedIndex(1);
68 | this.logLevel.setToolTipText("Log level");
69 | }
70 |
71 | private void setValues() {
72 | try {
73 | updateObject=false;
74 | enabled.setSelected(scriptRef.isEnabled());
75 | tfName.setText(scriptRef.getName());
76 | // tfDesc.setText(scriptRef.getDescription());
77 |
78 | requestScript.setText(scriptRef.getScriptRequest());
79 | responseScript.setText(scriptRef.getScriptResponse());
80 | cbScope.setSelected(scriptRef.isInScope());
81 | cbProxy.setSelected((scriptRef.getTools() & IBurpExtenderCallbacks.TOOL_PROXY) != 0);
82 | cbSpider.setSelected((scriptRef.getTools() & IBurpExtenderCallbacks.TOOL_SPIDER) != 0);
83 | cbScanner.setSelected((scriptRef.getTools() & IBurpExtenderCallbacks.TOOL_SCANNER) != 0);
84 | cbIntruder.setSelected((scriptRef.getTools() & IBurpExtenderCallbacks.TOOL_INTRUDER) != 0);
85 | cbRepeater.setSelected((scriptRef.getTools() & IBurpExtenderCallbacks.TOOL_REPEATER) != 0);
86 | cbSequencer.setSelected((scriptRef.getTools() & IBurpExtenderCallbacks.TOOL_SEQUENCER) != 0);
87 | cbExtension.setSelected((scriptRef.getTools() & IBurpExtenderCallbacks.TOOL_EXTENDER) != 0);
88 | cbSessionHandling.setSelected(scriptRef.isSessionHandling());
89 | cbIntruder.setEnabled(!scriptRef.isSessionHandling());
90 | cbProxy.setEnabled(!scriptRef.isSessionHandling());
91 | cbRepeater.setEnabled(!scriptRef.isSessionHandling());
92 | cbScanner.setEnabled(!scriptRef.isSessionHandling());
93 | cbSequencer.setEnabled(!scriptRef.isSessionHandling());
94 | cbExtension.setEnabled(!scriptRef.isSessionHandling());
95 | cbSpider.setEnabled(!scriptRef.isSessionHandling());
96 | } finally {
97 | updateObject=true;
98 | }
99 | }
100 |
101 | public void refresh() {
102 | SwingUtilities.invokeLater(this::setValues);
103 | }
104 |
105 | public JScrollPane getScrollPane() {
106 | return scrollPane;
107 | }
108 |
109 | @Override
110 | public void componentShown(ComponentEvent e) {
111 | }
112 |
113 | @Override
114 | public void componentHidden(ComponentEvent e) {
115 | }
116 |
117 | @Override
118 | public void componentMoved(ComponentEvent e) {
119 |
120 | }
121 |
122 | @Override
123 | public void componentResized(ComponentEvent e) {
124 | Dimension parentSize = getParent().getSize();
125 | Dimension d;
126 | int width = (int)parentSize.getWidth();
127 | int height = (int)parentSize.getHeight();
128 | d = new Dimension(width - 10, height - vSplitPane.getY() - 10);
129 | SwingUtilities.invokeLater(()-> ScriptPanel.this.vSplitPane.setPreferredSize(d));
130 | }
131 |
132 | /*private class ScriptComponentListener implements ComponentListener {
133 | }*/
134 |
135 | private class ScriptDocumentListener implements DocumentListener {
136 | @Override
137 | public void insertUpdate(DocumentEvent e) {
138 | update();
139 | }
140 |
141 | @Override
142 | public void removeUpdate(DocumentEvent e) {
143 | update();
144 | }
145 |
146 | @Override
147 | public void changedUpdate(DocumentEvent e) {
148 | update();
149 | }
150 |
151 | public void update() {
152 | if (updateObject) {
153 | scriptRef.setName(tfName.getText());
154 | // scriptRef.setDescription(tfDesc.getText());
155 | scriptRef.setScriptError(false);
156 | scriptRef.setScriptResponse(responseScript.getText());
157 | scriptRef.setScriptRequest(requestScript.getText());
158 | scriptRef.setSessionHandling(cbSessionHandling.isSelected());
159 | scriptRefChangeConsumer.accept(scriptRef, Action.UPDATE);
160 | }
161 | }
162 | }
163 |
164 | private void changeTools(int tools, boolean enabled) {
165 | if (enabled) {
166 | tools = scriptRef.getTools() | tools;
167 | } else {
168 | tools = scriptRef.getTools() & (tools ^ 0xFFFFFFFF);
169 | }
170 | scriptRef.setTools(tools);
171 | SwingUtilities.invokeLater(()-> scriptRefChangeConsumer.accept(scriptRef, Action.UPDATE));
172 | }
173 |
174 | public void buildUi() {
175 | int maxColumn = 9;
176 | int line = 0;
177 | setLayout(new GridBagLayout());
178 | add(enabled, new GridBagConstraints(0, line, 1, 1, 0.0, 0.0
179 | , LINE_START, NONE, new Insets(2, 2, 2, 2), 5, 5));
180 | add(cbScope, new GridBagConstraints(1, line, 2, 1, 0.0, 0.0
181 | , LINE_START, NONE, new Insets(2, 2, 2, 2), 5, 5));
182 | add(logLevel, new GridBagConstraints(3, line, 1, 1, 0.0, 0.0
183 | , LINE_START, NONE, new Insets(2, 2, 2, 2), 5, 5));
184 |
185 | JPanel savePanel = new JPanel();
186 | savePanel.setLayout(new FlowLayout());
187 | savePanel.add(btnRevert);
188 | savePanel.add(btnDelete);
189 | savePanel.add(btnSave);
190 | add(savePanel, new GridBagConstraints(4, line, maxColumn - 5, 1, 0.0, 0.0
191 | , LINE_END, NONE, new Insets(2, 2, 2, 2), 5, 5));
192 |
193 | add(labIntercept, new GridBagConstraints(0, ++line, 1, 1, 0.0, 0.0
194 | , LINE_START, NONE, new Insets(2, 2, 2, 2), 5, 5));
195 | addComponent(line, 1, cbProxy, cbSpider, cbScanner, cbIntruder, cbRepeater, cbSequencer, cbExtension);
196 | line = addTextFieldWithLabel(maxColumn, line, labelName, tfName);
197 | add(cbSessionHandling, new GridBagConstraints(0, ++line, maxColumn, 1, 0.0, 0.0
198 | , LINE_START, NONE, new Insets(2, 2, 2, 2), 5, 5));
199 | // line = addTextFieldWithLabel(maxColumn, line, labelDesc, tfDesc);
200 | add(color, new GridBagConstraints(0, ++line, maxColumn, 1, 0.0, 0.0
201 | , LINE_START, NONE, new Insets(2, 2, 2, 2), 5, 5));
202 | requestScript.setBorder(BorderFactory.createTitledBorder("Request script"));
203 | responseScript.setBorder(BorderFactory.createTitledBorder("Response script"));
204 | errorPane.setContentType("text/html");
205 | hSplitPane.setResizeWeight( 0.5 );
206 | vSplitPane.setResizeWeight(0.8);
207 |
208 | add(vSplitPane, new GridBagConstraints(0, ++line, maxColumn, 1, 1.0, 1.0
209 | , CENTER, BOTH, new Insets(2, 2, 2, 2), 5, 5));
210 | setValues();
211 | enabled.addItemListener(e->{
212 | scriptRef.setEnabled(enabled.isSelected());
213 | scriptRef.setScriptError(false);
214 | scriptRefChangeConsumer.accept(scriptRef, Action.UPDATE);
215 | });
216 | cbScope.addItemListener(e-> {
217 | scriptRef.setInScope(cbScope.isSelected());
218 | scriptRefChangeConsumer.accept(scriptRef, Action.UPDATE);
219 | });
220 | cbSessionHandling.addItemListener(e-> {
221 | scriptRef.setSessionHandling(cbSessionHandling.isSelected());
222 | SwingUtilities.invokeLater(()->{
223 | responseScript.setVisible(!cbSessionHandling.isSelected());
224 | if (!cbSessionHandling.isSelected()) {
225 | hSplitPane.setResizeWeight(0.5);
226 | hSplitPane.resetToPreferredSizes();
227 | cbIntruder.setEnabled(true);
228 | cbProxy.setEnabled(true);
229 | cbRepeater.setEnabled(true);
230 | cbScanner.setEnabled(true);
231 | cbSequencer.setEnabled(true);
232 | cbExtension.setEnabled(true);
233 | cbSpider.setEnabled(true);
234 | } else {
235 | cbIntruder.setEnabled(false);
236 | cbProxy.setEnabled(false);
237 | cbRepeater.setEnabled(false);
238 | cbScanner.setEnabled(false);
239 | cbSequencer.setEnabled(false);
240 | cbExtension.setEnabled(false);
241 | cbSpider.setEnabled(false);
242 | }
243 |
244 | });
245 | scriptRefChangeConsumer.accept(scriptRef, Action.UPDATE);
246 | });
247 |
248 | cbProxy.addItemListener(e->changeTools(IBurpExtenderCallbacks.TOOL_PROXY, cbProxy.isSelected()));
249 | cbSpider.addItemListener(e->changeTools(IBurpExtenderCallbacks.TOOL_SPIDER, cbSpider.isSelected()));
250 | cbScanner.addItemListener(e->changeTools(IBurpExtenderCallbacks.TOOL_SCANNER, cbScanner.isSelected()));
251 | cbIntruder.addItemListener(e->changeTools(IBurpExtenderCallbacks.TOOL_INTRUDER, cbIntruder.isSelected()));
252 | cbRepeater.addItemListener(e->changeTools(IBurpExtenderCallbacks.TOOL_REPEATER, cbRepeater.isSelected()));
253 | cbSequencer.addItemListener(e->changeTools(IBurpExtenderCallbacks.TOOL_SEQUENCER, cbSequencer.isSelected()));
254 | cbExtension.addItemListener(e->changeTools(IBurpExtenderCallbacks.TOOL_EXTENDER, cbExtension.isSelected()));
255 |
256 | tfName.getDocument().addDocumentListener(documentListener);
257 | // tfDesc.getDocument().addDocumentListener(documentListener);
258 | requestScript.addDocumentListener(documentListener);
259 | responseScript.addDocumentListener(documentListener);
260 |
261 | color.addItemListener(e-> SwingUtilities.invokeLater(()-> {
262 | requestScript.setColored(!color.isSelected());
263 | responseScript.setColored(!color.isSelected());
264 | }));
265 |
266 | addComponentListener(this);
267 | getParent().addComponentListener(this);
268 | btnRevert.addActionListener(l-> SwingUtilities.invokeLater(()->{
269 | boolean revert = JOptionPane.showConfirmDialog(this, "Are you sure you want to revert your changes ?", "Confirmation", JOptionPane.YES_NO_OPTION) == JOptionPane.OK_OPTION;
270 | if (revert) {
271 | scriptRef.restore();
272 | scriptRef.backup();
273 | setValues();
274 | scriptRefChangeConsumer.accept(scriptRef, Action.UPDATE);
275 | }
276 | }));
277 | btnSave.addActionListener(l-> SwingUtilities.invokeLater(()->{
278 | boolean save = JOptionPane.showConfirmDialog(this, "Are you sure you want to save your changes ?", "Confirmation", JOptionPane.YES_NO_OPTION) == JOptionPane.OK_OPTION;
279 | if (save) {
280 | scriptRefChangeConsumer.accept(scriptRef, Action.SAVE);
281 | }
282 | }));
283 | btnDelete.addActionListener(l-> SwingUtilities.invokeLater(()->{
284 | boolean delete = JOptionPane.showConfirmDialog(this, "Are you sure you want to delete this script ?", "Confirmation", JOptionPane.YES_NO_OPTION) == JOptionPane.OK_OPTION;
285 | if (delete) {
286 | scriptRefChangeConsumer.accept(scriptRef, Action.DELETE);
287 | }
288 | }));
289 | JPopupMenu popupMenu = new JPopupMenu();
290 | JMenuItem clear = new JMenuItem(new AbstractAction("Clear content") {
291 | @Override
292 | public void actionPerformed(ActionEvent e) {
293 | synchronized (contentQueue) {
294 | contentQueue.clear();
295 | contentQueueModified = true;
296 | }
297 | refreshLog();
298 | }
299 | });
300 | popupMenu.add(clear);
301 | errorPane.setComponentPopupMenu(popupMenu);
302 | }
303 |
304 | private int addTextFieldWithLabel(int maxColumn, int line, JLabel labelName, JTextField tfName) {
305 | add(labelName, new GridBagConstraints(0, ++line, 1, 1, 0.0, 0.0
306 | , LINE_START, NONE, new Insets(2, 2, 2, 2), 5, 5));
307 | add(tfName, new GridBagConstraints(1, line, maxColumn-2, 1, 1.0, 0.0
308 | , LINE_START, BOTH, new Insets(2, 2, 2, 2), 5, 5));
309 | return line;
310 | }
311 |
312 | private void addComponent(int line, int column, Component ...components) {
313 | for (Component c: components) {
314 | add(c, new GridBagConstraints(column++, line, 1, 1, 0.0, 0.0
315 | , LINE_START, NONE, new Insets(2, 2, 2, 2), 5, 5));
316 | }
317 | }
318 |
319 | public int getLogLevel() {
320 | return logLevel.getSelectedIndex();
321 | }
322 |
323 | public void refreshLog() {
324 | if (contentQueueModified) {
325 | SwingUtilities.invokeLater(()->{
326 | StringBuilder sb = new StringBuilder();
327 | sb.append("");
328 | synchronized (contentQueue) {
329 | contentQueue.forEach(sb::append);
330 | contentQueueModified = false;
331 | }
332 | sb.append("");
333 | this.errorPane.setText(sb.toString());
334 | });
335 | }
336 | }
337 | public void addLog(CharSequence content) {
338 | synchronized (contentQueue) {
339 | while (contentQueue.size()>1000) {
340 | contentQueue.removeFirst();
341 | }
342 | contentQueue.addLast(content);
343 | contentQueueModified = true;
344 | }
345 | }
346 |
347 |
348 | @Override
349 | public Dimension getPreferredScrollableViewportSize() {
350 | return super.getPreferredSize();
351 | }
352 |
353 |
354 | @Override
355 | public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
356 | return 16;
357 | }
358 |
359 | @Override
360 | public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
361 | return 16;
362 | }
363 |
364 | @Override
365 | public boolean getScrollableTracksViewportWidth() {
366 | return true;
367 | }
368 |
369 | @Override
370 | public boolean getScrollableTracksViewportHeight() {
371 | return false;
372 | }
373 |
374 | }
375 |
--------------------------------------------------------------------------------
/src/main/java/fr/safepic/burp/script/ui/panel/ScriptTablePanel.java:
--------------------------------------------------------------------------------
1 | package fr.safepic.burp.script.ui.panel;
2 |
3 | import fr.safepic.burp.script.PreferenceClass;
4 | import fr.safepic.burp.script.ui.component.CloseTabIcon;
5 | import fr.safepic.burp.script.ui.component.CloseableTabbedPane;
6 | import fr.safepic.burp.script.ui.model.ScriptRef;
7 | import fr.safepic.burp.script.ui.model.ScriptTableModel;
8 |
9 | import javax.swing.*;
10 | import java.awt.*;
11 | import java.awt.event.ActionEvent;
12 | import java.awt.event.ActionListener;
13 | import java.awt.event.MouseAdapter;
14 | import java.awt.event.MouseEvent;
15 | import java.util.ArrayList;
16 | import java.util.List;
17 | import java.util.prefs.BackingStoreException;
18 | import java.util.prefs.Preferences;
19 | import java.util.stream.Collectors;
20 |
21 | public class ScriptTablePanel extends JPanel {
22 | private JTable table;
23 | private ScriptTableModel tm;
24 | private final List data = new ArrayList<>();
25 | private final CloseableTabbedPane tabbedPane = new CloseableTabbedPane("Scripts", this, this::addTab);
26 | private final Timer timer;
27 |
28 |
29 | public ScriptTablePanel() {
30 | setName("Scripts");
31 | init();
32 | //tabbedPane.addChangeListener(this::tabChange);
33 | timer = new Timer(1000, e -> {
34 | oldSelectedIndex = tabbedPane.getSelectedIndex();
35 | Component c = tabbedPane.getComponentAt(oldSelectedIndex);
36 | if (c instanceof JScrollPane) {
37 | c = ((JScrollPane)c).getViewport().getView();
38 | if (c instanceof ScriptPanel) {
39 | ((ScriptPanel) c).refreshLog();
40 | }
41 | }
42 | });
43 | timer.setInitialDelay(5000);
44 | timer.start();
45 | }
46 |
47 | public Void addTab() {
48 | ScriptRef sr = fakeData("New script " + data.size());
49 | data.add(sr);
50 | SwingUtilities.invokeLater(()-> tm.fireTableDataChanged());
51 | addTab(sr);
52 | return null;
53 | }
54 |
55 | public CloseableTabbedPane getTabbedPane() {
56 | return tabbedPane;
57 | }
58 |
59 | private ScriptRef fakeData(String name) {
60 |
61 | ScriptRef scriptRef = new ScriptRef();
62 | scriptRef.setName(name);
63 | scriptRef.setDescription("");
64 | scriptRef.setScriptRequest("/* Variables exposed :\n" +
65 | "helper : instance of burp.IExtensionHelpers\n" +
66 | "requestResponse : instance of burp.IHttpRequestResponse\n" +
67 | "Right click to see code sample\n"+
68 | "*/\n");
69 | scriptRef.setScriptResponse("/* Variables exposed :\n" +
70 | "helper : instance of burp.IExtensionHelpers\n" +
71 | "requestResponse : instance of burp.IHttpRequestResponse\n" +
72 | "Right click to see code sample\n"+
73 | "*/\n");
74 | return scriptRef;
75 | }
76 |
77 | public void init() {
78 | setLayout(new BorderLayout());
79 | loadData();
80 |
81 | tm = new ScriptTableModel(data);
82 | table = new JTable(tm);
83 | for (int i = 0; i {
124 | if (sr.getPanel() == null) {
125 | if (!sr.needsSave()) {
126 | sr.backup();
127 | }
128 | ScriptPanel scriptPanel = new ScriptPanel(sr, ScriptTablePanel.this::onChange);
129 | sr.setPanel(scriptPanel);
130 | tabbedPane.addTab(sr.getName(), new CloseTabIcon(), scriptPanel.getScrollPane(), null, () -> {
131 | SwingUtilities.invokeLater(() -> {
132 | int idx = tabbedPane.indexOfComponent(scriptPanel.getScrollPane());
133 | sr.setPanel(null);
134 | tabbedPane.removeTabAt(idx);
135 | tabbedPane.setSelectedIndex(0);
136 | });
137 | return null;
138 | });
139 | scriptPanel.buildUi();
140 | }
141 | tabbedPane.setSelectedIndex(tabbedPane.indexOfComponent(sr.getPanel().getScrollPane()));
142 | });
143 | }
144 |
145 | public void loadData() {
146 | try {
147 | Preferences nodes = getNode();
148 | for (String child : getNode().childrenNames()) {
149 | data.add(ScriptRef.restoreData(nodes.node(child)));
150 | }
151 | } catch (BackingStoreException ignore) {
152 | }
153 | }
154 |
155 | public void onChange(ScriptRef ref, ScriptPanel.Action action) {
156 | if (action == ScriptPanel.Action.UPDATE) {
157 | SwingUtilities.invokeLater(()-> {
158 | tm.fireDataChanged(ref);
159 | JPanel panel = ref.getPanel();
160 | if (panel != null) {
161 | int idx = tabbedPane.indexOfComponent(ref.getPanel().getScrollPane());
162 | tabbedPane.setTitleAt(idx, ref.getName());
163 | }
164 | });
165 | } else if (action == ScriptPanel.Action.SAVE) {
166 | try {
167 | ref.saveData(getNode());
168 | ref.backup();
169 | SwingUtilities.invokeLater(()-> tm.fireDataChanged(ref));
170 | } catch (BackingStoreException ignore) {
171 | }
172 | } else if (action == ScriptPanel.Action.DELETE) {
173 | Preferences node = getNode();
174 | try {
175 | if (node.nodeExists(ref.getUid())) {
176 | node.node(ref.getUid()).removeNode();
177 | }
178 | node.flush();
179 | } catch (BackingStoreException ignore) {
180 | }
181 | if (data.contains(ref)) {
182 | data.remove(ref);
183 | SwingUtilities.invokeLater(()-> tm.fireTableDataChanged());
184 | }
185 | }
186 | }
187 |
188 | private Preferences getNode() {
189 | return Preferences.userNodeForPackage(PreferenceClass.class);
190 | }
191 |
192 | public List getActiveScriptRef() {
193 | return data.stream().filter(ScriptRef::isEnabled).collect(Collectors.toList());
194 | }
195 |
196 | public void notifyScriptDisabled(ScriptRef ref) {
197 | SwingUtilities.invokeLater(()-> tm.fireDataChanged(ref));
198 | }
199 | }
200 |
--------------------------------------------------------------------------------
/src/main/java/fr/safepic/burp/script/ui/panel/TabbedPanel.java:
--------------------------------------------------------------------------------
1 | package fr.safepic.burp.script.ui.panel;
2 |
3 | import javax.swing.*;
4 | import java.awt.*;
5 |
6 | public class TabbedPanel extends JPanel {
7 | final ScriptTablePanel refPanel;
8 |
9 | public TabbedPanel() {
10 | setLayout(new BorderLayout());
11 | refPanel = new ScriptTablePanel();
12 | add(refPanel.getTabbedPane(), BorderLayout.CENTER);
13 | }
14 |
15 | public void unload() {
16 |
17 | }
18 |
19 |
20 | public ScriptTablePanel getScriptListPanel() {
21 | return refPanel;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Change IP Port/Http.txt:
--------------------------------------------------------------------------------
1 | setTarget(false, 'www.google.com', 80);
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Change IP Port/Https.txt:
--------------------------------------------------------------------------------
1 | setTarget(true, 'www.google.com', 443);
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Common Action/Prefix URL.txt:
--------------------------------------------------------------------------------
1 | setUrl('/html'+getUrl());
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Common Action/Set User-Agent.txt:
--------------------------------------------------------------------------------
1 | setRequestHeader('User-Agent', 'My value');
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Common Action/Set-Method.txt:
--------------------------------------------------------------------------------
1 | setMethod('POST');
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Issues - Burp Pro only/Add confidence certain.txt:
--------------------------------------------------------------------------------
1 | addIssue('My issue').certain();
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Issues - Burp Pro only/Add confidence firm.txt:
--------------------------------------------------------------------------------
1 | addIssue('My issue').firm();
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Issues - Burp Pro only/Add confidence tentative.txt:
--------------------------------------------------------------------------------
1 | addIssue('My issue').tentative();
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Issues - Burp Pro only/Add severity high.txt:
--------------------------------------------------------------------------------
1 | addIssue('My issue').high();
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Issues - Burp Pro only/Add severity information.txt:
--------------------------------------------------------------------------------
1 | addIssue('My issue');
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Issues - Burp Pro only/Add severity medium .txt:
--------------------------------------------------------------------------------
1 | addIssue('My issue').medium();
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Issues - Burp Pro only/Add severitylow.txt:
--------------------------------------------------------------------------------
1 | addIssue('My issue').low();
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Issues - Burp Pro only/Add with issue detail.txt:
--------------------------------------------------------------------------------
1 | addIssue('My issue').issue("Issue detail", "Issue background");
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Issues - Burp Pro only/Add with remediation detail.txt:
--------------------------------------------------------------------------------
1 | addIssue('My issue').remediation("Remediation detail", "Remediation background");
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Log/Error.txt:
--------------------------------------------------------------------------------
1 | error('Error level trace');
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Log/Info.txt:
--------------------------------------------------------------------------------
1 | info('Info level trace');
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Log/Verbose.txt:
--------------------------------------------------------------------------------
1 | verbose('Verbose level trace');
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Macro/Access Macro Json.txt:
--------------------------------------------------------------------------------
1 | json = macros[0].getResponseBodyAsJson('UTF-8');
2 | token = json.token;
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Mark/Add Comment.txt:
--------------------------------------------------------------------------------
1 | setComment('My Comment');
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Mark/Highlight in red.txt:
--------------------------------------------------------------------------------
1 | /*red, orange, yellow, green, cyan, blue, pink, magenta, gray*/
2 | setColor('red');
3 |
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Request Header/Add header.txt:
--------------------------------------------------------------------------------
1 | addRequestHeader('Cookie', 'My value');
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Request Header/Add or replace.txt:
--------------------------------------------------------------------------------
1 | setRequestHeader('Cookie', 'My value');
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Request Header/Remove by name.txt:
--------------------------------------------------------------------------------
1 | removeRequestHeader('Cookie');
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Request Header/Replace existing header.txt:
--------------------------------------------------------------------------------
1 | updateRequestHeader('Cookie', 'My value');
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Request Header/Retrieve all header by name.txt:
--------------------------------------------------------------------------------
1 | // headerValue is an array
2 | var headerValue = getRequestHeaders('Cookie');
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Request Header/Retrieve first header by name.txt:
--------------------------------------------------------------------------------
1 | var headerValue = getRequestHeader('Cookie');
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/RequestBody/Replace Json value.txt:
--------------------------------------------------------------------------------
1 | /*
2 | Body:
3 | {
4 | "data": "mydata"
5 | }
6 | */
7 | json = getRequestBodyAsJson('UTF-8');
8 | json.data = "new data";
9 | setRequestBodyAsJson(json);
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/RequestBody/Replace-Request-By-File-Content.txt:
--------------------------------------------------------------------------------
1 | setRequestAsFile('/home/kali/request.txt');
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/RequestBody/retrieve body.txt:
--------------------------------------------------------------------------------
1 | getRequestBody('utf-8');
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/RequestBody/set body.txt:
--------------------------------------------------------------------------------
1 | setRequestBody('Body');
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Response Header/Add header.txt:
--------------------------------------------------------------------------------
1 | addResponseHeader('Set-Cookie', 'My value');
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Response Header/Add or replace.txt:
--------------------------------------------------------------------------------
1 | setResponseHeader('Set-Cookie', 'My value');
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Response Header/Remove by name.txt:
--------------------------------------------------------------------------------
1 | removeResponseHeader('Set-Cookie');
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Response Header/Replace existing header.txt:
--------------------------------------------------------------------------------
1 | updateResponseHeader('Set-Cookie', 'My value');
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Response Header/Retrieve all header by name.txt:
--------------------------------------------------------------------------------
1 | // headerValue is an array
2 | var headerValue = getResponseHeaders('Set-Cookie');
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Response Header/Retrieve first header by name.txt:
--------------------------------------------------------------------------------
1 | var headerValue = getResponseHeader('Set-Cookie');
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/ResponseBody/retrieve body.txt:
--------------------------------------------------------------------------------
1 | getResponseBody('utf-8');
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/ResponseBody/set body.txt:
--------------------------------------------------------------------------------
1 | setResponseBody('Body');
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Test Value/Method.txt:
--------------------------------------------------------------------------------
1 | if (getMethod()=='PUT') {
2 | // Your code goes here
3 | }
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Test Value/Request header value.txt:
--------------------------------------------------------------------------------
1 | if (hasRequestHeader('Connection', 'Close')) {
2 | // Your code goes here
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Test Value/Response header value.txt:
--------------------------------------------------------------------------------
1 | if (hasResponseHeader('Connection', 'Close')) {
2 | // Your code goes here
3 | }
--------------------------------------------------------------------------------
/src/main/resources/sample-menu-item/Test Value/Url value.txt:
--------------------------------------------------------------------------------
1 | if (getUrl()=='/test') {
2 | // Your code goes here
3 | }
--------------------------------------------------------------------------------