diff --git a/README.md b/README.md index 6f981fc..9582b84 100644 --- a/README.md +++ b/README.md @@ -32,11 +32,14 @@ interface from source, then click "Open". 5. Click "Next" to load the plugin. -Within the Notes tab, there are four options: +Within the Notes tab, you can: - Save Notes: Save any currently open documents to a file. - Load Notes: Load a previously saved set of notes from a file. -- Add Text: Add a tab with a new text document. -- Add Spreadsheet: Add a tab with a new spreadsheet. +- New Text: Add a tab with a new text document. +- Import Text: Load the contents of a text document. +- New Spreadsheet: Add a tab with a new spreadsheet. +- Import Spreadsheet: Load the contents of a CSV document. +- You can also export individual notes tabs to an external file. From other tabs in Burp, right clicking in areas where a user can normally interact with HTTP Responses and Requests, such as the Proxy History or Site Map diff --git a/build/jar/BurpNotesExtension.jar b/build/jar/BurpNotesExtension.jar index e38b42c..b11fda4 100644 Binary files a/build/jar/BurpNotesExtension.jar and b/build/jar/BurpNotesExtension.jar differ diff --git a/src/burp/BurpExtender.java b/src/burp/BurpExtender.java index f88e4f7..d74fab4 100644 --- a/src/burp/BurpExtender.java +++ b/src/burp/BurpExtender.java @@ -13,6 +13,8 @@ package burp; import java.awt.Component; +import java.awt.BorderLayout; +import java.awt.Dimension; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -21,6 +23,7 @@ import java.util.List; import javax.swing.JButton; +import javax.swing.JComboBox; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; @@ -39,7 +42,6 @@ public class BurpExtender implements IBurpExtender, ITab, ActionListener, IExtensionStateListener, IContextMenuFactory { private NotesExtensionOperations ops; - private JButton btnAddText, btnAddSpreadsheet, btnLoadNotes, btnSaveNotes; public final String TAB_NAME = "Notes"; @@ -70,27 +72,62 @@ public void registerExtenderCallbacks(final IBurpExtenderCallbacks Callbacks) public void run(){ //Create our initial UI components ops.tabbedPane = new JTabbedPane(); - JPanel panel = new JPanel(); + JPanel panel = new JPanel(new BorderLayout()); + //Tab Management + ops.tabList = new JComboBox(); + ops.tabList.addItem("Choose..."); + ops.btnSaveTabAsTemplate = new JButton("Export Tab"); + ops.btnSaveTabAsTemplate.setActionCommand(NotesExtensionOperations.COMMAND_SAVE_TAB_AS_TEMPLATE); + ops.btnSaveTabAsTemplate.addActionListener(BurpExtender.this); + ops.btnRemoveTab = new JButton("Remove Tab"); + ops.btnRemoveTab.setActionCommand(NotesExtensionOperations.COMMAND_REMOVE_TAB); + ops.btnRemoveTab.addActionListener(BurpExtender.this); + //Add the save,load, and document buttons - btnAddText = new JButton("Add Text"); - btnAddText.setActionCommand(NotesExtensionOperations.COMMAND_ADD_TEXT); - btnAddText.addActionListener(BurpExtender.this); - btnAddSpreadsheet = new JButton("Add Spreadsheet"); - btnAddSpreadsheet.setActionCommand(NotesExtensionOperations.COMMAND_ADD_SPREADSHEET); - btnAddSpreadsheet.addActionListener(BurpExtender.this); - btnSaveNotes = new JButton("Save Notes"); - btnSaveNotes.setActionCommand(NotesExtensionOperations.COMMAND_SAVE_NOTES); - btnSaveNotes.addActionListener(BurpExtender.this); - btnLoadNotes = new JButton("Load Notes"); - btnLoadNotes.setActionCommand(NotesExtensionOperations.COMMAND_LOAD_NOTES); - btnLoadNotes.addActionListener(BurpExtender.this); + ops.btnAddText = new JButton("New Text"); + ops.btnAddText.setActionCommand(NotesExtensionOperations.COMMAND_ADD_TEXT); + ops.btnAddText.addActionListener(BurpExtender.this); + ops.btnAddSpreadsheet = new JButton("New Spreadsheet"); + ops.btnAddSpreadsheet.setActionCommand(NotesExtensionOperations.COMMAND_ADD_SPREADSHEET); + ops.btnAddSpreadsheet.addActionListener(BurpExtender.this); + ops.btnImportText = new JButton("Import Text"); + ops.btnImportText.setActionCommand(NotesExtensionOperations.COMMAND_IMPORT_TEXT); + ops.btnImportText.addActionListener(BurpExtender.this); + ops.btnImportSpreadsheet = new JButton("Import Spreadsheet"); + ops.btnImportSpreadsheet.setActionCommand(NotesExtensionOperations.COMMAND_IMPORT_SPREADSHEET); + ops.btnImportSpreadsheet.addActionListener(BurpExtender.this); + ops.btnSaveNotes = new JButton("Save Notes"); + ops.btnSaveNotes.setActionCommand(NotesExtensionOperations.COMMAND_SAVE_NOTES); + ops.btnSaveNotes.addActionListener(BurpExtender.this); + ops.btnLoadNotes = new JButton("Load Notes"); + ops.btnLoadNotes.setActionCommand(NotesExtensionOperations.COMMAND_LOAD_NOTES); + ops.btnLoadNotes.addActionListener(BurpExtender.this); //Make our panel with a grid layout for arranging the buttons - panel.setLayout(new GridLayout(3, 3)); - panel.add(btnSaveNotes); - panel.add(btnLoadNotes); - panel.add(btnAddText); - panel.add(btnAddSpreadsheet); + JPanel topPanel = new JPanel(); + topPanel.add(ops.tabList); + topPanel.add(ops.btnSaveTabAsTemplate); + topPanel.add(ops.btnRemoveTab); + topPanel.setPreferredSize(new Dimension(500,100)); + panel.add(topPanel, BorderLayout.PAGE_START); + JPanel spaceLeft = new JPanel(); + spaceLeft.setPreferredSize(new Dimension(300,200)); + panel.add(spaceLeft, BorderLayout.LINE_START); + JPanel buttonPanel = new JPanel(new GridLayout(3,2)); + buttonPanel.add(ops.btnSaveNotes); + buttonPanel.add(ops.btnLoadNotes); + buttonPanel.add(ops.btnAddText); + buttonPanel.add(ops.btnAddSpreadsheet); + buttonPanel.add(ops.btnImportText); + buttonPanel.add(ops.btnImportSpreadsheet); + buttonPanel.setPreferredSize(new Dimension(150,150)); + panel.add(buttonPanel, BorderLayout.CENTER); + JPanel spaceRight = new JPanel(); + spaceRight.setPreferredSize(new Dimension(300,200)); + panel.add(spaceRight, BorderLayout.LINE_END); + JPanel spaceBottom = new JPanel(); + spaceBottom.setPreferredSize(new Dimension(500,250)); + panel.add(spaceBottom, BorderLayout.PAGE_END); ops.tabbedPane.addTab("Main", panel); ops.callbacks.customizeUiComponent(ops.tabbedPane); @@ -122,7 +159,7 @@ public void extensionUnloaded() { //Unloading extension, prompt user to save data if they have any tabs if(ops.tabbedPane.getTabCount() > 1){ Object[] options = {"Yes", "No"}; - int n = JOptionPane.showOptionDialog(getUiComponent(), "Would you like to save your notes?", "Notes Tab", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); + int n = JOptionPane.showOptionDialog(ops.tabbedPane, "Would you like to save your notes?", "Notes Tab", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); if(n == JOptionPane.YES_OPTION){ ops.SaveNotes(); } diff --git a/src/com/trustwave/burp/ButtonTabComponent.java b/src/com/trustwave/burp/ButtonTabComponent.java index 30ecea6..bf54aa3 100644 --- a/src/com/trustwave/burp/ButtonTabComponent.java +++ b/src/com/trustwave/burp/ButtonTabComponent.java @@ -50,14 +50,16 @@ @SuppressWarnings("serial") public class ButtonTabComponent extends JPanel { private final JTabbedPane pane; + private final NotesExtensionOperations ops; - public ButtonTabComponent(final JTabbedPane pane) { + public ButtonTabComponent(final JTabbedPane pane, final NotesExtensionOperations ops) { //unset default FlowLayout' gaps super(new FlowLayout(FlowLayout.LEFT, 0, 0)); if (pane == null) { throw new NullPointerException("TabbedPane is null"); } this.pane = pane; + this.ops = ops; setOpaque(false); //make JLabel read titles from JTabbedPane @@ -105,11 +107,7 @@ public TabButton() { public void actionPerformed(ActionEvent e) { int i = pane.indexOfTabComponent(ButtonTabComponent.this); if (i != -1) { - Object[] options = {"OK", "Cancel"}; - int n = JOptionPane.showOptionDialog(pane, "If you close this tab you will lose any unsaved data.", "Notes Tab", JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[0]); - if(n == JOptionPane.OK_OPTION){ - pane.remove(i); - } + ops.RemoveTab(i); } } diff --git a/src/com/trustwave/burp/NotesExtensionOperations.java b/src/com/trustwave/burp/NotesExtensionOperations.java index ef81fa3..bdabb61 100644 --- a/src/com/trustwave/burp/NotesExtensionOperations.java +++ b/src/com/trustwave/burp/NotesExtensionOperations.java @@ -16,6 +16,8 @@ import java.awt.event.ActionListener; import java.io.File; import java.io.FileReader; +import java.io.BufferedReader; +import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; @@ -24,6 +26,7 @@ import java.util.List; import javax.swing.JButton; +import javax.swing.JComboBox; import javax.swing.JFileChooser; import javax.swing.JMenu; import javax.swing.JMenuItem; @@ -47,17 +50,26 @@ public class NotesExtensionOperations{ public IExtensionHelpers helpers; public PrintWriter stdout, errout; public JTabbedPane tabbedPane; - public JButton btnAddText, btnAddSpreadsheet, btnLoadNotes, btnSaveNotes; + public JComboBox tabList; + public JButton btnAddText, btnAddSpreadsheet, btnImportText, btnImportSpreadsheet, btnLoadNotes, btnSaveNotes, btnSaveTabAsTemplate, btnRemoveTab; public HashMap tabTypes; public IHttpRequestResponse[] messages; public byte selectedContext; + public ArrayList spreadsheetTemplateFile; + public String textTemplateFile; //KEYWORDS public static final String COMMAND_ADD_TEXT = "addText"; public static final String COMMAND_ADD_SPREADSHEET = "addSpreadsheet"; + public static final String COMMAND_IMPORT_TEXT = "importText"; + public static final String COMMAND_IMPORT_SPREADSHEET = "importSpreadsheet"; public static final String COMMAND_LOAD_NOTES = "loadNotes"; public static final String COMMAND_SAVE_NOTES = "saveNotes"; public static final String COMMAND_ADD_NEW_TEXT = "newTextDoc"; + public static final String COMMAND_SAVE_TAB_AS_TEMPLATE = "saveTabAsTemplate"; + public static final String COMMAND_REMOVE_TAB = "removeTab"; + public static final int TEMPLATE_TEXT = 1; + public static final int TEMPLATE_SPREADSHEET = 2; //Constructor /** @@ -75,8 +87,9 @@ public NotesExtensionOperations(IBurpExtenderCallbacks Callbacks){ * @param saveFile True - Show a Save Dialog. False - Show a Load Dialog. * @return The File chosen by the user. */ - public File GetFileFromDialog(boolean saveFile){ + public File GetFileFromDialog(boolean saveFile, String defaultName){ JFileChooser fc = new JFileChooser(); + if(defaultName != "") fc.setSelectedFile(new File(defaultName)); int returnVal; if(saveFile) returnVal = fc.showSaveDialog(tabbedPane); else returnVal = fc.showOpenDialog(tabbedPane); @@ -110,7 +123,7 @@ public void SaveNotes(){ ArrayList data = GetNotesData(); if(data.size() > 0) { File f; - if((f = GetFileFromDialog(true)) != null){ + if((f = GetFileFromDialog(true, "notes.txt")) != null){ try{ //Create our various Writers FileWriter fw = new FileWriter(f); @@ -135,7 +148,7 @@ public void LoadNotes(){ //Now pick file to load File file; try { - if((file = GetFileFromDialog(false)) != null){ + if((file = GetFileFromDialog(false, "")) != null){ ArrayList spreadData = new ArrayList(); if(file.exists() && file.isFile() && file.canRead()){ CSVReader reader = new CSVReader(new FileReader(file)); @@ -232,6 +245,7 @@ public void SetNotesData(ArrayList data){ //Start text object inText = true; inTitle = true; + current = ""; } else if(nextLine[j].equals("ENDTEXT")){ //End of text object, create the new textArea and add the tab inText = false; @@ -260,7 +274,7 @@ public void SetNotesData(ArrayList data){ inTitle = false; } else { spreadData.add(nextLine); - i = nextLine.length; //End this loop early, we are taking the whole line + j = nextLine.length; //End this loop early, we are taking the whole line } } } @@ -285,8 +299,10 @@ public Component GetInnerComponent(int tabIndex){ /** * Add a blank text tab to the Tabbed Pane. Will prompt the user for a name. */ - public void AddTextTab(){ - AddTextTab(""); + public void AddTextTab(boolean importFile){ + if(importFile) promptUseTemplate(TEMPLATE_TEXT); + if(textTemplateFile != null) AddTextTab(textTemplateFile); + else AddTextTab(""); } /** @@ -309,6 +325,8 @@ public void AddTextTab(String text, String name){ //Create a JTextArea for displaying plain text JTextArea newText = new JTextArea(5,30); newText.setText(text); + //Clear template for next file if it was used + textTemplateFile = null; //Set it in a scroll pane JScrollPane scrollWindow = new JScrollPane(newText); scrollWindow.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); @@ -318,16 +336,19 @@ public void AddTextTab(String text, String name){ newText.setBounds(tabbedPane.getBounds()); //Mark the tab as a TEXT tab tabTypes.put(name, "TEXT"); + tabList.addItem(name); tabbedPane.addTab(name, scrollWindow); - tabbedPane.setTabComponentAt(tabbedPane.getTabCount() - 1, new ButtonTabComponent(tabbedPane)); + tabbedPane.setTabComponentAt(tabbedPane.getTabCount() - 1, new ButtonTabComponent(tabbedPane, this)); } /** * Add a new blank spreadsheet to the Tabbed Pane. Will prompt the user for a name. */ - public void AddSpreadsheetTab(){ - AddSpreadsheetTab(null); + public void AddSpreadsheetTab(boolean importFile){ + if(importFile) promptUseTemplate(TEMPLATE_SPREADSHEET); + if(spreadsheetTemplateFile != null) AddSpreadsheetTab(spreadsheetTemplateFile); + else AddSpreadsheetTab(null); } /** @@ -373,8 +394,12 @@ public void AddSpreadsheetTab(ArrayList data, String name){ //Set this tab as a spreadsheet tabTypes.put(name, "SPREADSHEET"); + tabList.addItem(name); tabbedPane.addTab(name, scrollWindow); - tabbedPane.setTabComponentAt(tabbedPane.getTabCount() - 1, new ButtonTabComponent(tabbedPane)); + tabbedPane.setTabComponentAt(tabbedPane.getTabCount() - 1, new ButtonTabComponent(tabbedPane, this)); + + //Make sure the template is null at this point for the next new tab + spreadsheetTemplateFile = null; } /** @@ -401,11 +426,163 @@ public String getTabName(){ String newName = ""; while(newName == "" || tabTypes.containsKey(newName)) { - newName = JOptionPane.showInputDialog("Please enter a unique name for the document:"); + newName = JOptionPane.showInputDialog(tabbedPane, "Please enter a unique name for the document:"); } return newName; } + /** + * Prompt the user to choose a template file for a new spreadsheet. + * @return The name entered by the user. + */ + public void promptUseTemplate(int templateType){ + //Pick a file to import and fill in a new tab + File file; + try { + if(templateType == TEMPLATE_TEXT){ + if((file = GetFileFromDialog(false, "TEMPLATE.txt")) != null){ + textTemplateFile = ""; + if(file.exists() && file.isFile() && file.canRead()){ + FileReader input = new FileReader(file); + BufferedReader br = new BufferedReader(input); + String strLine; + //Read File Line By Line + while ((strLine = br.readLine()) != null) { + // Print the content on the console + textTemplateFile += strLine + "\n"; + } + //Close the input stream + br.close(); + } + } + } else if(templateType == TEMPLATE_SPREADSHEET){ + if((file = GetFileFromDialog(false, "TEMPLATE.csv")) != null){ + spreadsheetTemplateFile = new ArrayList(); + if(file.exists() && file.isFile() && file.canRead()){ + CSVReader reader = new CSVReader(new FileReader(file)); + String[] nextLine; + while((nextLine = reader.readNext()) != null){ + spreadsheetTemplateFile.add(nextLine); + } + reader.close(); + } + } + } + } catch (IOException exc) { + errout.println(exc.getMessage()); + } + } + + /** + * Remove the tab at the specified index + * @param index The index of the tab to remove. + */ + public void RemoveTab(int index){ + Object[] options = {"OK", "Cancel"}; + int n = JOptionPane.showOptionDialog(tabbedPane, "If you close this tab you will lose any unsaved data.", "Notes Tab", JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[0]); + if(n == JOptionPane.OK_OPTION){ + String name = tabbedPane.getTitleAt(index); + tabList.removeItem(name); + tabTypes.remove(name); + tabbedPane.remove(index); + } + } + + public void ClearAllTabs(){ + Object[] options = {"Yes", "No"}; + int n = JOptionPane.showOptionDialog(tabbedPane, "Do you want to clear all open tabs?", "Notes Tab", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[0]); + if(n == JOptionPane.YES_OPTION){ + for(int i = tabbedPane.getTabCount() - 1; i > 0; i--){ + String name = tabbedPane.getTitleAt(i); + tabList.removeItem(name); + tabTypes.remove(name); + tabbedPane.remove(i); + } + } + } + + /** + * Save the content of the spreadsheet tab as a template CSV + * @param index The index of the tab to save. + */ + public void ExportTab(int index){ + String name = tabbedPane.getTitleAt(index); + String type = tabTypes.get(name); + if(type == "SPREADSHEET"){ + ExportSpreadsheetTab(index); + } else if(type == "TEXT"){ + ExportTextTab(index); + } + } + + public void ExportTextTab(int index){ + //Text tab + JTextArea textTab = (JTextArea) GetInnerComponent(index); + + if(textTab != null){ + //Text + String data = textTab.getText(); + + if(data != null ){ + File f; + if((f = GetFileFromDialog(true, "TEMPLATE.txt")) != null){ + try{ + // Create file + FileWriter fstream = new FileWriter(f); + BufferedWriter out = new BufferedWriter(fstream); + out.write(data); + //Close the output stream + out.close(); + } catch (Exception exc){//Catch exception if any + errout.println(exc.getMessage()); + } + } + } + } + } + + public void ExportSpreadsheetTab(int index){ + stdout.println("Exporting Tab Data"); + //ArrayList to store data we will write out + ArrayList data = new ArrayList(); + JTable table = (JTable) GetInnerComponent(index); + + if(table != null){ + //Data + int numColumns = table.getColumnCount(); + String[] row; + // Write cell data + for(int i=0;i 0) { + File f; + if((f = GetFileFromDialog(true, "TEMPLATE.csv")) != null){ + try{ + //Create our various Writers + FileWriter fw = new FileWriter(f); + CSVWriter writer = new CSVWriter(fw); + //Write out to file and close + writer.writeAll(data); + writer.close(); + fw.close(); + } catch(IOException exc){ + errout.println(exc.getMessage()); + } + } + } else { + //No notes could be found + } + } + } + //CONTEXT MENU OPERATIONS /** * Create menu items for a context menu on behalf of the Burp Extension's createMenuItems(). @@ -481,14 +658,24 @@ public static JMenuItem CreateMenuItem(String name, String command, ActionListen */ public void ParseAction(String cmd){ if(cmd.equals(COMMAND_ADD_TEXT)){ - AddTextTab(); + AddTextTab(false); } else if(cmd.equals(COMMAND_ADD_SPREADSHEET)){ - AddSpreadsheetTab(); + AddSpreadsheetTab(false); + } else if(cmd.equals(COMMAND_IMPORT_TEXT)){ + AddTextTab(true); + } else if(cmd.equals(COMMAND_IMPORT_SPREADSHEET)){ + AddSpreadsheetTab(true); } else if(cmd.equals(COMMAND_SAVE_NOTES)){ SaveNotes(); } else if(cmd.equals(COMMAND_LOAD_NOTES)){ + if(tabbedPane.getTabCount() > 1) ClearAllTabs(); LoadNotes(); - } else { + } else if(cmd.equals(COMMAND_SAVE_TAB_AS_TEMPLATE)){ + if(tabList.getSelectedIndex() > 0) ExportTab(tabList.getSelectedIndex()); + } else if(cmd.equals(COMMAND_REMOVE_TAB)){ + if(tabList.getSelectedIndex() > 0) RemoveTab(tabList.getSelectedIndex()); + } + else { ParseConCommand(cmd); } }