/***********************************************************************
*
* $CVSHeader$
*
* This file is part of WebScarab, an Open Web Application Security
* Project utility. For details, please see http://www.owasp.org/
*
* Copyright (c) 2002 - 2004 Rogan Dawes
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Getting Source
* ==============
*
* Source for this application is maintained at Sourceforge.net, a
* repository for free software projects.
*
* For details, please see http://www.sourceforge.net/projects/owasp
*
*/
/*
* SpiderPanel.java
*
* Created on August 6, 2003, 10:01 PM
*/
package org.owasp.webscarab.plugin.spider.swing;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import org.owasp.webscarab.model.ConversationID;
import org.owasp.webscarab.model.HttpUrl;
import org.owasp.webscarab.plugin.spider.Link;
import org.owasp.webscarab.plugin.spider.Spider;
import org.owasp.webscarab.plugin.spider.SpiderModel;
import org.owasp.webscarab.plugin.spider.SpiderUI;
import org.owasp.webscarab.ui.swing.HeaderPanel;
import org.owasp.webscarab.ui.swing.SwingPluginUI;
import org.owasp.webscarab.ui.swing.UrlTreeModelAdapter;
import org.owasp.webscarab.ui.swing.UrlTreeRenderer;
import org.owasp.webscarab.util.swing.ColumnDataModel;
/**
*
* @author rdawes
*/
public class SpiderPanel extends javax.swing.JPanel implements SwingPluginUI, SpiderUI {
/**
*
*/
private static final long serialVersionUID = 8563871484142539698L;
private SpiderModel _model;
private Spider _spider;
private Logger _logger = Logger.getLogger(this.getClass().getName());
private HeaderPanel _hp;
/** Creates new form SpiderPanel */
public SpiderPanel(Spider spider) {
initComponents();
_hp = new HeaderPanel();
_hp.setEditable(true);
_spider = spider;
_model = _spider.getModel();
TreeModel treeModel = new UrlTreeModelAdapter(_model.getUrlModel());
unseenLinkTree.setModel(treeModel);
unseenLinkTree.setRootVisible(false);
unseenLinkTree.setShowsRootHandles(true);
unseenLinkTree.setCellRenderer(new UrlTreeRenderer());
configure();
}
public javax.swing.JPanel getPanel() {
return this;
}
public String getPluginName() {
return new String("Spider");
}
private void configure() {
recursiveCheckBox.setSelected(_model.getRecursive());
cookieSyncCheckBox.setSelected(_model.getCookieSync());
domainRegexTextField.setText(_model.getAllowedDomains());
pathRegexTextField.setText(_model.getForbiddenPaths());
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
private void initComponents() {//GEN-BEGIN:initComponents
java.awt.GridBagConstraints gridBagConstraints;
jLabel1 = new javax.swing.JLabel();
domainRegexTextField = new javax.swing.JTextField();
jLabel2 = new javax.swing.JLabel();
pathRegexTextField = new javax.swing.JTextField();
recursiveCheckBox = new javax.swing.JCheckBox();
stopButton = new javax.swing.JButton();
cookieSyncCheckBox = new javax.swing.JCheckBox();
linkTreePanel = new javax.swing.JPanel();
jScrollPane2 = new javax.swing.JScrollPane();
unseenLinkTree = new javax.swing.JTree();
linkTreeFetchSelectionButton = new javax.swing.JButton();
linkTreeFetchTreeButton = new javax.swing.JButton();
headerButton = new javax.swing.JButton();
setLayout(new java.awt.GridBagLayout());
jLabel1.setText("Allowed Domains");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
add(jLabel1, gridBagConstraints);
domainRegexTextField.setToolTipText("A regular expression describing which domains to include");
domainRegexTextField.setMinimumSize(new java.awt.Dimension(60, 19));
domainRegexTextField.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
domainRegexTextFieldActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 1.0;
add(domainRegexTextField, gridBagConstraints);
jLabel2.setText("Forbidden Paths");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 2;
gridBagConstraints.gridy = 0;
add(jLabel2, gridBagConstraints);
pathRegexTextField.setToolTipText("A regular expression describing which paths to exclude");
pathRegexTextField.setMinimumSize(new java.awt.Dimension(60, 19));
pathRegexTextField.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
pathRegexTextFieldActionPerformed(evt);
}
});
pathRegexTextField.addFocusListener(new java.awt.event.FocusAdapter() {
public void focusLost(java.awt.event.FocusEvent evt) {
pathRegexTextFieldFocusLost(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 3;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 1.0;
add(pathRegexTextField, gridBagConstraints);
recursiveCheckBox.setText("Fetch Recursively");
recursiveCheckBox.setToolTipText("Enables recursive fetching of Links");
recursiveCheckBox.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING);
recursiveCheckBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
recursiveCheckBoxActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 2;
gridBagConstraints.gridy = 1;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
add(recursiveCheckBox, gridBagConstraints);
stopButton.setText("Stop");
stopButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
stopButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 2;
gridBagConstraints.gridy = 3;
add(stopButton, gridBagConstraints);
cookieSyncCheckBox.setText("Synchronise cookies");
cookieSyncCheckBox.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING);
cookieSyncCheckBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cookieSyncCheckBoxActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
add(cookieSyncCheckBox, gridBagConstraints);
linkTreePanel.setLayout(new java.awt.GridBagLayout());
jScrollPane2.setViewportView(unseenLinkTree);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
linkTreePanel.add(jScrollPane2, gridBagConstraints);
linkTreeFetchSelectionButton.setText("Fetch Selection");
linkTreeFetchSelectionButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
linkTreeFetchSelectionButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 1;
gridBagConstraints.weightx = 1.0;
linkTreePanel.add(linkTreeFetchSelectionButton, gridBagConstraints);
linkTreeFetchTreeButton.setText("Fetch Tree");
linkTreeFetchTreeButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
linkTreeFetchTreeButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.weightx = 1.0;
linkTreePanel.add(linkTreeFetchTreeButton, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
add(linkTreePanel, gridBagConstraints);
headerButton.setText("Headers");
headerButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
headerButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 3;
add(headerButton, gridBagConstraints);
}//GEN-END:initComponents
private void headerButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_headerButtonActionPerformed
_hp.setHeaders(_model.getExtraHeaders());
JOptionPane.showMessageDialog(this, _hp, "Spider Extra Headers", JOptionPane.PLAIN_MESSAGE);
_model.setExtraHeaders(_hp.getHeaders());
}//GEN-LAST:event_headerButtonActionPerformed
private void cookieSyncCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cookieSyncCheckBoxActionPerformed
_model.setCookieSync(cookieSyncCheckBox.isSelected());
}//GEN-LAST:event_cookieSyncCheckBoxActionPerformed
private void linkTreeFetchTreeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_linkTreeFetchTreeButtonActionPerformed
TreePath[] selection = unseenLinkTree.getSelectionPaths();
if (selection != null && selection.length==1) {
if (_spider.isBusy()) {
_logger.warning("Spider is still busy, please wait");
JOptionPane.showMessageDialog(SpiderPanel.this, "Spider is still busy, please wait");
return;
}
HttpUrl url = (HttpUrl) selection[0].getLastPathComponent();
_spider.requestLinksUnder(url);
} else {
_logger.info("Cannot fetch a tree if there are 0 or many paths selected!");
JOptionPane.showMessageDialog(SpiderPanel.this, "Cannot fetch a tree if there are 0 or many paths selected!");
}
}//GEN-LAST:event_linkTreeFetchTreeButtonActionPerformed
private void linkTreeFetchSelectionButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_linkTreeFetchSelectionButtonActionPerformed
TreePath[] selection = unseenLinkTree.getSelectionPaths();
if (selection == null || selection.length == 0) return;
if (_spider.isBusy()) {
_logger.warning("Spider is still busy, please wait");
// FIXME show a message
return;
}
unseenLinkTree.clearSelection();
HttpUrl[] urls = new HttpUrl[selection.length];
for (int i=0; i<selection.length; i++) {
urls[i] = (HttpUrl) selection[i].getLastPathComponent();
}
_spider.requestLinks(urls);
}//GEN-LAST:event_linkTreeFetchSelectionButtonActionPerformed
private void pathRegexTextFieldFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_pathRegexTextFieldFocusLost
//_model.setForbiddenPaths(pathRegexTextField.getText());
}//GEN-LAST:event_pathRegexTextFieldFocusLost
private void pathRegexTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pathRegexTextFieldActionPerformed
_model.setForbiddenPaths(pathRegexTextField.getText());
}//GEN-LAST:event_pathRegexTextFieldActionPerformed
private void domainRegexTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_domainRegexTextFieldActionPerformed
_model.setAllowedDomains(domainRegexTextField.getText());
}//GEN-LAST:event_domainRegexTextFieldActionPerformed
private void stopButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_stopButtonActionPerformed
_spider.clearQueue();
}//GEN-LAST:event_stopButtonActionPerformed
private void recursiveCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_recursiveCheckBoxActionPerformed
_model.setRecursive(recursiveCheckBox.isSelected());
}//GEN-LAST:event_recursiveCheckBoxActionPerformed
public Action[] getConversationActions() {
return null;
}
public Action[] getUrlActions() {
return new Action[] {new SpiderAction()};
}
public void linkDequeued(final Link link, final int queueSize) {
if (SwingUtilities.isEventDispatchThread()) {
if (link != null) {
// _logger.info(queueSize + " in queue, fetching " + link.getURL());
} else {
// _logger.info("Cleared queue");
}
} else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
linkDequeued(link, queueSize);
}
});
}
}
public void linkQueued(final Link link, final int queueSize) {
if (SwingUtilities.isEventDispatchThread()) {
_logger.fine(queueSize + " in queue, adding: " + link.getURL());
} else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
linkQueued(link, queueSize);
}
});
}
}
public void setEnabled(final boolean enabled) {
if (SwingUtilities.isEventDispatchThread()) {
cookieSyncCheckBox.setEnabled(enabled);
domainRegexTextField.setEnabled(enabled);
linkTreeFetchSelectionButton.setEnabled(enabled);
linkTreeFetchTreeButton.setEnabled(enabled);
pathRegexTextField.setEnabled(enabled);
recursiveCheckBox.setEnabled(enabled);
stopButton.setEnabled(enabled);
} else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
setEnabled(enabled);
}
});
}
}
public ColumnDataModel<ConversationID>[] getConversationColumns() {
return null;
}
public ColumnDataModel<HttpUrl>[] getUrlColumns() {
return null;
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JCheckBox cookieSyncCheckBox;
private javax.swing.JTextField domainRegexTextField;
private javax.swing.JButton headerButton;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JScrollPane jScrollPane2;
private javax.swing.JButton linkTreeFetchSelectionButton;
private javax.swing.JButton linkTreeFetchTreeButton;
private javax.swing.JPanel linkTreePanel;
private javax.swing.JTextField pathRegexTextField;
private javax.swing.JCheckBox recursiveCheckBox;
private javax.swing.JButton stopButton;
private javax.swing.JTree unseenLinkTree;
// End of variables declaration//GEN-END:variables
private class SpiderAction extends AbstractAction {
/**
*
*/
private static final long serialVersionUID = -2207351321290083769L;
public SpiderAction() {
putValue(NAME, "Spider tree");
putValue(SHORT_DESCRIPTION, "Fetches any unseen links below this point");
putValue("URL", null);
}
public void actionPerformed(java.awt.event.ActionEvent e) {
Object o = getValue("URL");
if (o == null || !(o instanceof HttpUrl)) return;
HttpUrl url = (HttpUrl) o;
if (! _spider.isBusy()) {
_spider.requestLinksUnder(url);
} else {
_logger.warning("Spider is still busy, please wait");
JOptionPane.showMessageDialog(SpiderPanel.this, "Spider is still busy, please wait");
}
}
public void putValue(String key, Object value) {
super.putValue(key, value);
if (key != null && key.equals("URL")) {
if (value != null && value instanceof HttpUrl) {
this.setEnabled(true);
} else {
this.setEnabled(false);
}
}
}
}
}