/* * Zed Attack Proxy (ZAP) and its related class files. * * ZAP is an HTTP/HTTPS proxy for assessing web application security. * * Copyright 2012 cosminstefanxp [at] gmail [.] com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Note that this extension and the other classes in this package are heavily * based on the original Paros OptionsSpiderPanel! */ package org.zaproxy.zap.extension.spider; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Component; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import javax.swing.BorderFactory; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSlider; import javax.swing.SortOrder; import javax.swing.border.Border; import javax.swing.border.EmptyBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.plaf.basic.BasicComboBoxRenderer; import org.parosproxy.paros.Constant; import org.parosproxy.paros.model.Model; import org.parosproxy.paros.model.OptionsParam; import org.parosproxy.paros.view.AbstractParamPanel; import org.parosproxy.paros.view.View; import org.zaproxy.zap.spider.DomainAlwaysInScopeMatcher; import org.zaproxy.zap.spider.SpiderParam; import org.zaproxy.zap.spider.SpiderParam.HandleParametersOption; import org.zaproxy.zap.utils.ZapNumberSpinner; import org.zaproxy.zap.view.AbstractMultipleOptionsTablePanel; import org.zaproxy.zap.view.LayoutHelper; import org.zaproxy.zap.view.PositiveValuesSlider; /** * The Class OptionsSpiderPanel defines the Options Panel showed when configuring settings related to the * spider. */ public class OptionsSpiderPanel extends AbstractParamPanel { /** The Constant serialVersionUID. */ private static final long serialVersionUID = -5623691753271231473L; /** The full panel for the spider options. */ private JPanel panelSpider = null; // The controls for the options: private JSlider sliderMaxDepth = null; private JSlider sliderThreads = null; private ZapNumberSpinner durationNumberSpinner = null; private ZapNumberSpinner maxChildrenNumberSpinner; private JCheckBox chkPostForm = null; private JCheckBox chkProcessForm = null; private JCheckBox parseComments = null; private JCheckBox parseRobotsTxt = null; private JCheckBox parseSitemapXml = null; private JCheckBox parseSVNEntries = null; private JCheckBox parseGit = null; private JCheckBox handleODataSpecificParameters = null; private JCheckBox chkSendRefererHeader; private DomainsAlwaysInScopeMultipleOptionsPanel domainsAlwaysInScopePanel; private DomainsAlwaysInScopeTableModel domainsAlwaysInScopeTableModel; private JComboBox<HandleParametersOption> handleParameters = null; /** * Instantiates a new options spider panel. */ public OptionsSpiderPanel() { super(); initialize(); } /** * This method initializes this options Panel. */ private void initialize() { this.setLayout(new CardLayout()); this.setName(Constant.messages.getString("spider.options.title")); if (Model.getSingleton().getOptionsParam().getViewParam().getWmUiHandlingOption() == 0) { this.setSize(314, 245); } this.add(getPanelSpider(), getPanelSpider().getName()); } /** * This method initializes the main panel containing all option controls. * * @return the panel for the spider options. */ private JPanel getPanelSpider() { if (panelSpider == null) { // Initialize the panel panelSpider = new JPanel(new BorderLayout()); if (Model.getSingleton().getOptionsParam().getViewParam().getWmUiHandlingOption() == 0) { panelSpider.setSize(114, 150); } panelSpider.setName(""); // Prepare the necessary labels JLabel domainsLabel = new JLabel(); JLabel noThreadsLabel = new JLabel(); JLabel maxDuration = new JLabel(); JLabel maxDepthLabel = new JLabel(); JLabel handleParametersLabel = new JLabel(); maxDepthLabel.setText(Constant.messages.getString("spider.options.label.depth")); noThreadsLabel.setText(Constant.messages.getString("spider.options.label.threads")); maxDuration.setText(Constant.messages.getString("spider.options.label.duration")); domainsLabel.setText(Constant.messages.getString("spider.options.label.domains")); handleParametersLabel.setText(Constant.messages.getString("spider.options.label.handleparameters")); JPanel innerPanel = new JPanel(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.weightx = 1.0D; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.anchor = GridBagConstraints.NORTHWEST; Insets insets = new Insets(2, 2, 2, 2); gbc.insets = insets; // Add the components on the panel innerPanel.add(maxDepthLabel, gbc); innerPanel.add(getSliderMaxDepth(), gbc); innerPanel.add(noThreadsLabel, gbc); innerPanel.add(getSliderThreads(), gbc); JPanel inlineOptionsPanel = new JPanel(new GridBagLayout()); inlineOptionsPanel.add(maxDuration, LayoutHelper.getGBC(0, 0, 1, 1.0D)); inlineOptionsPanel.add(getDurationNumberSpinner(), LayoutHelper.getGBC(1, 0, 1, 1.0D)); inlineOptionsPanel.add( new JLabel(Constant.messages.getString("spider.options.label.maxChildren")), LayoutHelper.getGBC(0, 1, 1, 1.0D)); inlineOptionsPanel.add(getMaxChildrenNumberSpinner(), LayoutHelper.getGBC(1, 1, 1, 1.0D)); innerPanel.add(inlineOptionsPanel, gbc); innerPanel.add(domainsLabel, gbc); gbc.fill = GridBagConstraints.BOTH; gbc.weighty = 1.0D; innerPanel.add(getDomainsAlwaysInScopePanel(), gbc); gbc.fill = GridBagConstraints.HORIZONTAL; gbc.weighty = 0; innerPanel.add(getChkSendRefererHeader(), gbc); innerPanel.add(handleParametersLabel, gbc); innerPanel.add(getComboHandleParameters(), gbc); innerPanel.add(getChkProcessForm(), gbc); insets.left = 15; innerPanel.add(getChkPostForm(), gbc); insets.left = 2; innerPanel.add(getChkParseComments(), gbc); innerPanel.add(getChkParseRobotsTxt(), gbc); innerPanel.add(getChkParseSitemapXml(), gbc); innerPanel.add(getChkParseSVNEntries(), gbc); innerPanel.add(getChkParseGit(), gbc); innerPanel.add(getHandleODataSpecificParameters(), gbc); JScrollPane scrollPane = new JScrollPane(innerPanel); scrollPane.setBorder(BorderFactory.createEmptyBorder()); panelSpider.add(scrollPane, BorderLayout.CENTER); } return panelSpider; } @Override public void initParam(Object obj) { OptionsParam options = (OptionsParam) obj; SpiderParam param = options.getParamSet(SpiderParam.class); getSliderMaxDepth().setValue(param.getMaxDepth()); getSliderThreads().setValue(param.getThreadCount()); getDurationNumberSpinner().setValue(param.getMaxDuration()); getMaxChildrenNumberSpinner().setValue(param.getMaxChildren()); getDomainsAlwaysInScopeTableModel().setDomainsAlwaysInScope(param.getDomainsAlwaysInScope()); getDomainsAlwaysInScopePanel().setRemoveWithoutConfirmation(param.isConfirmRemoveDomainAlwaysInScope()); getChkProcessForm().setSelected(param.isProcessForm()); getChkSendRefererHeader().setSelected(param.isSendRefererHeader()); getChkPostForm().setSelected(param.isPostForm()); getChkParseComments().setSelected(param.isParseComments()); getChkParseRobotsTxt().setSelected(param.isParseRobotsTxt()); getChkParseSitemapXml().setSelected(param.isParseSitemapXml()); getChkParseSVNEntries().setSelected(param.isParseSVNEntries()); getChkParseGit().setSelected(param.isParseGit()); getComboHandleParameters().setSelectedItem(param.getHandleParameters()); getHandleODataSpecificParameters().setSelected(param.isHandleODataParametersVisited()); } @Override public void saveParam(Object obj) throws Exception { OptionsParam options = (OptionsParam) obj; SpiderParam param = options.getParamSet(SpiderParam.class); param.setMaxDepth(getSliderMaxDepth().getValue()); param.setThreadCount(getSliderThreads().getValue()); param.setMaxDuration(getDurationNumberSpinner().getValue()); param.setMaxChildren(getMaxChildrenNumberSpinner().getValue()); param.setDomainsAlwaysInScope(getDomainsAlwaysInScopeTableModel().getDomainsAlwaysInScope()); param.setConfirmRemoveDomainAlwaysInScope(getDomainsAlwaysInScopePanel().isRemoveWithoutConfirmation()); param.setSendRefererHeader(getChkSendRefererHeader().isSelected()); param.setProcessForm(getChkProcessForm().isSelected()); param.setPostForm(getChkPostForm().isSelected()); param.setParseComments(getChkParseComments().isSelected()); param.setParseRobotsTxt(getChkParseRobotsTxt().isSelected()); param.setParseSitemapXml(getChkParseSitemapXml().isSelected()); param.setParseSVNEntries(getChkParseSVNEntries().isSelected()); param.setParseGit(getChkParseGit().isSelected()); param.setHandleParameters((HandleParametersOption) getComboHandleParameters().getSelectedItem()); param.setHandleODataParametersVisited(getHandleODataSpecificParameters().isSelected()); } /** * This method initializes the slider for MaxDepth. * * @return the slider for max depth */ private JSlider getSliderMaxDepth() { if (sliderMaxDepth == null) { sliderMaxDepth = new JSlider(); sliderMaxDepth.setMaximum(19); sliderMaxDepth.setMinimum(1); sliderMaxDepth.setMinorTickSpacing(1); sliderMaxDepth.setPaintTicks(true); sliderMaxDepth.setPaintLabels(true); sliderMaxDepth.setName(""); sliderMaxDepth.setMajorTickSpacing(1); sliderMaxDepth.setSnapToTicks(true); sliderMaxDepth.setPaintTrack(true); } return sliderMaxDepth; } /** * This method initializes the slider for maximum number of threads used. * * @return javax.swing.JSlider */ private JSlider getSliderThreads() { if (sliderThreads == null) { sliderThreads = new PositiveValuesSlider(Constant.MAX_THREADS_PER_SCAN); } return sliderThreads; } private ZapNumberSpinner getDurationNumberSpinner() { if (durationNumberSpinner == null) { durationNumberSpinner = new ZapNumberSpinner(0, 0, Integer.MAX_VALUE); } return durationNumberSpinner; } private ZapNumberSpinner getMaxChildrenNumberSpinner() { if (maxChildrenNumberSpinner == null) { maxChildrenNumberSpinner = new ZapNumberSpinner(0, 0, Integer.MAX_VALUE); } return maxChildrenNumberSpinner; } private JCheckBox getChkSendRefererHeader() { if (chkSendRefererHeader == null) { chkSendRefererHeader = new JCheckBox(Constant.messages.getString("spider.options.label.sendRefererHeader")); } return chkSendRefererHeader; } /** * This method initializes the checkbox for POST form option. This option should not be enabled if the * forms are not processed at all. * * @return javax.swing.JCheckBox */ private JCheckBox getChkPostForm() { if (chkPostForm == null) { chkPostForm = new JCheckBox(); chkPostForm.setText(Constant.messages.getString("spider.options.label.post")); if (!getChkProcessForm().isSelected()){ chkPostForm.setEnabled(false); } } return chkPostForm; } /** * This method initializes the checkbox for process form option. * * @return javax.swing.JCheckBox */ private JCheckBox getChkProcessForm() { if (chkProcessForm == null) { chkProcessForm = new JCheckBox(); chkProcessForm.setText(Constant.messages.getString("spider.options.label.processform")); // Code for controlling the status of the chkPostForm chkProcessForm.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent ev) { if (chkProcessForm.isSelected()) { chkPostForm.setEnabled(true); } else { chkPostForm.setEnabled(false); } } }); } return chkProcessForm; } /** * This method initializes the Parse Comments checkbox. * * @return javax.swing.JCheckBox */ private JCheckBox getChkParseComments() { if (parseComments == null) { parseComments = new JCheckBox(); parseComments.setText(Constant.messages.getString("spider.options.label.comments")); } return parseComments; } /** * This method initializes the Parse robots.txt checkbox. * * @return javax.swing.JCheckBox */ private JCheckBox getChkParseRobotsTxt() { if (parseRobotsTxt == null) { parseRobotsTxt = new JCheckBox(); parseRobotsTxt.setText(Constant.messages.getString("spider.options.label.robotstxt")); } return parseRobotsTxt; } /** * This method initializes the Parse sitemap.xml checkbox. * * @return javax.swing.JCheckBox */ private JCheckBox getChkParseSitemapXml() { if (parseSitemapXml == null) { parseSitemapXml = new JCheckBox(); parseSitemapXml.setText(Constant.messages.getString("spider.options.label.sitemapxml")); } return parseSitemapXml; } /** * This method initializes the Parse "SVN Entries" checkbox. * * @return javax.swing.JCheckBox */ private JCheckBox getChkParseSVNEntries() { if (parseSVNEntries == null) { parseSVNEntries = new JCheckBox(); parseSVNEntries.setText(Constant.messages.getString("spider.options.label.svnentries")); } return parseSVNEntries; } /** * This method initializes the Parse "Git" checkbox. * * @return javax.swing.JCheckBox */ private JCheckBox getChkParseGit() { if (parseGit == null) { parseGit = new JCheckBox(); parseGit.setText(Constant.messages.getString("spider.options.label.git")); } return parseGit; } /** * This method initializes the Handle OData-specific parameters checkbox. * * @return javax.swing.JCheckBox */ private JCheckBox getHandleODataSpecificParameters() { if (handleODataSpecificParameters == null) { handleODataSpecificParameters = new JCheckBox(); handleODataSpecificParameters.setText(Constant.messages.getString("spider.options.label.handlehodataparameters")); } return handleODataSpecificParameters; } /** * This method initializes the combobox for HandleParameters option. * * @return the combo handle parameters */ @SuppressWarnings("unchecked") private JComboBox<HandleParametersOption> getComboHandleParameters() { if (handleParameters == null) { handleParameters = new JComboBox<>(new HandleParametersOption[] { HandleParametersOption.USE_ALL, HandleParametersOption.IGNORE_VALUE, HandleParametersOption.IGNORE_COMPLETELY }); handleParameters.setRenderer(new HandleParametersOptionRenderer()); } return handleParameters; } private DomainsAlwaysInScopeMultipleOptionsPanel getDomainsAlwaysInScopePanel() { if (domainsAlwaysInScopePanel == null) { domainsAlwaysInScopePanel = new DomainsAlwaysInScopeMultipleOptionsPanel(getDomainsAlwaysInScopeTableModel()); } return domainsAlwaysInScopePanel; } private DomainsAlwaysInScopeTableModel getDomainsAlwaysInScopeTableModel() { if (domainsAlwaysInScopeTableModel == null) { domainsAlwaysInScopeTableModel = new DomainsAlwaysInScopeTableModel(); } return domainsAlwaysInScopeTableModel; } /** * A renderer for properly displaying the name of the HandleParametersOptions in a ComboBox. */ private static class HandleParametersOptionRenderer extends BasicComboBoxRenderer { private static final long serialVersionUID = 3654541772447187317L; private static final Border BORDER = new EmptyBorder(2, 3, 3, 3); @Override @SuppressWarnings("rawtypes") public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); if (value != null) { setBorder(BORDER); HandleParametersOption item = (HandleParametersOption) value; setText(item.getName()); } return this; } } /** * This method initializes the help index. * * @return the help index */ @Override public String getHelpIndex() { return "ui.dialogs.options.spider"; } private static class DomainsAlwaysInScopeMultipleOptionsPanel extends AbstractMultipleOptionsTablePanel<DomainAlwaysInScopeMatcher> { private static final long serialVersionUID = 2332044353650231701L; private static final String REMOVE_DIALOG_TITLE = Constant.messages.getString("spider.options.domains.in.scope.dialog.remove.title"); private static final String REMOVE_DIALOG_TEXT = Constant.messages.getString("spider.options.domains.in.scope.dialog.remove.text"); private static final String REMOVE_DIALOG_CONFIRM_BUTTON_LABEL = Constant.messages.getString("spider.options.domains.in.scope.dialog.remove.button.confirm"); private static final String REMOVE_DIALOG_CANCEL_BUTTON_LABEL = Constant.messages.getString("spider.options.domains.in.scope.dialog.remove.button.cancel"); private static final String REMOVE_DIALOG_CHECKBOX_LABEL = Constant.messages.getString("spider.options.domains.in.scope.dialog.remove.checkbox.label"); private DialogAddDomainAlwaysInScope addDialog = null; private DialogModifyDomainAlwaysInScope modifyDialog = null; public DomainsAlwaysInScopeMultipleOptionsPanel(DomainsAlwaysInScopeTableModel model) { super(model); getTable().setVisibleRowCount(5); getTable().setSortOrder(2, SortOrder.ASCENDING); } @Override public DomainAlwaysInScopeMatcher showAddDialogue() { if (addDialog == null) { addDialog = new DialogAddDomainAlwaysInScope(View.getSingleton().getOptionsDialog(null)); addDialog.pack(); } addDialog.setVisible(true); DomainAlwaysInScopeMatcher hostAuthentication = addDialog.getDomainAlwaysInScope(); addDialog.clear(); return hostAuthentication; } @Override public DomainAlwaysInScopeMatcher showModifyDialogue(DomainAlwaysInScopeMatcher e) { if (modifyDialog == null) { modifyDialog = new DialogModifyDomainAlwaysInScope(View.getSingleton().getOptionsDialog(null)); modifyDialog.pack(); } modifyDialog.setDomainAlwaysInScope(e); modifyDialog.setVisible(true); DomainAlwaysInScopeMatcher excludedDomain = modifyDialog.getDomainAlwaysInScope(); modifyDialog.clear(); if (!excludedDomain.equals(e)) { return excludedDomain; } return null; } @Override public boolean showRemoveDialogue(DomainAlwaysInScopeMatcher e) { JCheckBox removeWithoutConfirmationCheckBox = new JCheckBox(REMOVE_DIALOG_CHECKBOX_LABEL); Object[] messages = { REMOVE_DIALOG_TEXT, " ", removeWithoutConfirmationCheckBox }; int option = JOptionPane.showOptionDialog( View.getSingleton().getMainFrame(), messages, REMOVE_DIALOG_TITLE, JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, new String[] { REMOVE_DIALOG_CONFIRM_BUTTON_LABEL, REMOVE_DIALOG_CANCEL_BUTTON_LABEL }, null); if (option == JOptionPane.OK_OPTION) { setRemoveWithoutConfirmation(removeWithoutConfirmationCheckBox.isSelected()); return true; } return false; } } }