All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.zaproxy.zap.control.AddOnRunIssuesUtils Maven / Gradle / Ivy

Go to download

The Zed Attack Proxy (ZAP) is an easy to use integrated penetration testing tool for finding vulnerabilities in web applications. It is designed to be used by people with a wide range of security experience and as such is ideal for developers and functional testers who are new to penetration testing. ZAP provides automated scanners as well as a set of tools that allow you to find security vulnerabilities manually.

There is a newer version: 2.15.0
Show newest version
/*
 * Zed Attack Proxy (ZAP) and its related class files.
 * 
 * ZAP is an HTTP/HTTPS proxy for assessing web application security.
 * 
 * Copyright 2015 The ZAP Development Team
 * 
 * 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.
 */
package org.zaproxy.zap.control;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;

import org.apache.commons.lang.SystemUtils;
import org.apache.log4j.Logger;
import org.jdesktop.swingx.JXTree;
import org.parosproxy.paros.Constant;
import org.parosproxy.paros.view.View;

/**
 * An utility/helper class that extract textual representations of running issues of add-ons and show warning messages of
 * add-ons that can not be run.
 *
 * @since 2.4.0
 */
public final class AddOnRunIssuesUtils {

    private static final Logger LOGGER = Logger.getLogger(AddOnRunIssuesUtils.class);

    private AddOnRunIssuesUtils() {
    }

    /**
     * Shows a warning dialogue with the add-ons and its corresponding running issues or the issues if is extensions.
     * 

* The dialogue is composed with the given {@code message} and a tree in which are shown the add-ons and its issues as child * nodes of the add-ons. * * @param message the main message shown in the dialogue * @param availableAddOns the add-ons that are available, used to create and check the running issues * @param addOnsNotRunnable the add-ons with running issues that will be shown in the tree */ public static void showWarningMessageAddOnsNotRunnable( String message, AddOnCollection availableAddOns, Collection addOnsNotRunnable) { Object[] msgs = { message, createScrollableTreeAddOnsNotRunnable( availableAddOns, addOnsNotRunnable.toArray(new AddOn[addOnsNotRunnable.size()])) }; JOptionPane.showMessageDialog( View.getSingleton().getMainFrame(), msgs, Constant.PROGRAM_NAME, JOptionPane.WARNING_MESSAGE); } /** * Creates a scrollable tree with the given add-ons as root nodes and its issues as child nodes. * * @param availableAddOns the add-ons that are available, used to create check the running issues * @param addOnsNotRunnable the add-ons with running issues that will be shown in the tree * @return the tree wrapper in a {@code JSCrollPane} */ private static JScrollPane createScrollableTreeAddOnsNotRunnable( final AddOnCollection availableAddOns, AddOn... addOnsNotRunnable) { AddOnSearcher addOnSearcher = new AddOnSearcher() { @Override public AddOn searchAddOn(String id) { return availableAddOns.getAddOn(id); } }; DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(""); for (AddOn addOn : addOnsNotRunnable) { DefaultMutableTreeNode addOnNode = new DefaultMutableTreeNode(addOn.getName()); AddOn.AddOnRunRequirements requirements = addOn.calculateRunRequirements(availableAddOns.getAddOns()); List issues = getUiRunningIssues(requirements, addOnSearcher); if (issues.isEmpty()) { issues.addAll(getUiExtensionsRunningIssues(requirements, addOnSearcher)); } for (String issue : issues) { addOnNode.add(new DefaultMutableTreeNode(issue)); } rootNode.add(addOnNode); } JXTree tree = new JXTree(new DefaultTreeModel(rootNode)); tree.setVisibleRowCount(5); tree.setEditable(false); tree.setRootVisible(false); tree.setShowsRootHandles(true); tree.expandAll(); return new JScrollPane(tree); } /** * Shows a confirmation dialogue (yes-no question), with the given message at the top, followed by a tree in which is shown * the add-on with its corresponding running issues and, at the bottom before the yes and no buttons, the given question. * * @param message the main message shown in the dialogue * @param question the questions shown at the bottom of the dialogue, before the buttons * @param availableAddOns the add-ons that are available, used to create check the running issues * @param addOnNotRunnable the add-on with running issues that will be shown in the tree * @return {@code true} if it is confirmed, {@code false} otherwise */ public static boolean askConfirmationAddOnNotRunnable( String message, String question, AddOnCollection availableAddOns, AddOn addOnNotRunnable) { Object[] msgs = { message, createScrollableTreeAddOnsNotRunnable(availableAddOns, addOnNotRunnable), question }; return JOptionPane.showConfirmDialog( View.getSingleton().getMainFrame(), msgs, Constant.PROGRAM_NAME, JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION; } /** * Returns the textual representations of the running issues (Java version and dependency), if any. *

* The messages are internationalised thus suitable for UI components. * * @param requirements the run requirements of the add-on * @param addOnSearcher the class responsible for searching add-ons with a given id, used to search for add-ons that are * missing for the add-on * @return a {@code List} containing all the running issues of the add-on, empty if none * @see #getRunningIssues(AddOn.BaseRunRequirements) * @see #getUiExtensionsRunningIssues(AddOn.AddOnRunRequirements, AddOnSearcher) */ public static List getUiRunningIssues(AddOn.BaseRunRequirements requirements, AddOnSearcher addOnSearcher) { List issues = new ArrayList<>(2); if (requirements.isNewerJavaVersionRequired()) { if (requirements.getAddOn() != requirements.getAddOnMinimumJavaVersion()) { issues.add(MessageFormat.format( Constant.messages.getString("cfu.warn.addon.with.missing.requirements.javaversion.dependency"), requirements.getMinimumJavaVersion(), (SystemUtils.JAVA_VERSION == null ? Constant.messages.getString("cfu.warn.unknownJavaVersion") : SystemUtils.JAVA_VERSION), requirements.getAddOnMinimumJavaVersion().getName())); } else { issues.add(MessageFormat.format( Constant.messages.getString("cfu.warn.addon.with.missing.requirements.javaversion"), requirements.getMinimumJavaVersion(), (SystemUtils.JAVA_VERSION == null ? Constant.messages.getString("cfu.warn.unknownJavaVersion") : SystemUtils.JAVA_VERSION))); } } if (requirements.hasDependencyIssue()) { List issueDetails = requirements.getDependencyIssueDetails(); AddOn addOn; String message = null; switch (requirements.getDependencyIssue()) { case CYCLIC: message = Constant.messages.getString("cfu.warn.addon.with.missing.requirements.addon.id"); break; case OLDER_VERSION: // Do not set a message, the state is already reported as requiring an update. break; case MISSING: String addOnId = (String) issueDetails.get(0); if (addOnSearcher != null) { addOn = addOnSearcher.searchAddOn(addOnId); } else { addOn = null; } if (addOn == null) { message = MessageFormat.format( Constant.messages.getString("cfu.warn.addon.with.missing.requirements.addon.id"), addOnId); } else { message = MessageFormat.format( Constant.messages.getString("cfu.warn.addon.with.missing.requirements.addon"), addOn.getName()); } break; case PACKAGE_VERSION_NOT_BEFORE: addOn = (AddOn) issueDetails.get(0); message = MessageFormat.format( Constant.messages.getString("cfu.warn.addon.with.missing.requirements.addon.version.notBefore"), addOn.getName(), issueDetails.get(1), Integer.valueOf(addOn.getFileVersion())); break; case PACKAGE_VERSION_NOT_FROM: addOn = (AddOn) issueDetails.get(0); message = MessageFormat.format( Constant.messages.getString("cfu.warn.addon.with.missing.requirements.addon.version.notAfter"), addOn.getName(), issueDetails.get(1), Integer.valueOf(addOn.getFileVersion())); break; case VERSION: addOn = (AddOn) issueDetails.get(0); if (addOn.getVersion() == null) { message = MessageFormat.format( Constant.messages.getString("cfu.warn.addon.with.missing.requirements.addon.semver.notAvailable"), addOn.getName(), issueDetails.get(1)); } else { message = MessageFormat.format( Constant.messages.getString("cfu.warn.addon.with.missing.requirements.addon.semver"), addOn.getName(), issueDetails.get(1), addOn.getVersion()); } break; default: message = Constant.messages.getString("cfu.warn.addon.with.missing.requirements.unknown"); LOGGER.warn("Failed to handle dependency issue with name \"" + requirements.getDependencyIssue().name() + "\" and details: " + issueDetails); break; } if (message != null) { issues.add(message); } } return issues; } /** * Returns the textual representations of the running issues (Java version and dependency) of the extensions of hte add-on, * if any. *

* The messages are internationalised thus suitable for UI components. * * @param requirements the run requirements of the add-on, whose extensions' run requirements will be used * @param addOnSearcher the class responsible for searching add-ons with a given id, used to search for add-ons that are * missing for the add-on * @return a {@code List} containing all the running issues of the add-on, empty if none * @see #getRunningIssues(AddOn.BaseRunRequirements) * @see #getUiExtensionsRunningIssues(AddOn.AddOnRunRequirements, AddOnSearcher) */ public static List getUiExtensionsRunningIssues(AddOn.AddOnRunRequirements requirements, AddOnSearcher addOnSearcher) { if (!requirements.hasExtensionsWithRunningIssues()) { return new ArrayList<>(0); } List issues = new ArrayList<>(10); for (AddOn.ExtensionRunRequirements extReqs : requirements.getExtensionRequirements()) { issues.addAll(getUiRunningIssues(extReqs, addOnSearcher)); } return issues; } /** * Returns the textual representations of the running issues (Java version and dependency), if any. *

* The messages are not internationalised, should be used only for logging and non UI uses. * * @param requirements the run requirements of the add-on or extension * @return a {@code List} containing all the running issues of the add-on or extension, empty if none * @see #getUiRunningIssues(AddOn.BaseRunRequirements, AddOnSearcher) * @see #getUiExtensionsRunningIssues(AddOn.AddOnRunRequirements, AddOnSearcher) */ public static List getRunningIssues(AddOn.BaseRunRequirements requirements) { List issues = new ArrayList<>(2); String issue = getJavaVersionIssue(requirements); if (issue != null) { issues.add(issue); } issue = getDependencyIssue(requirements); if (issue != null) { issues.add(issue); } return issues; } /** * Returns the textual representation of the issues that prevent the extensions of the add-on from being run, if any. *

* The messages are not internationalised, should be used only for logging and non UI uses. * * @param requirements the run requirements of the add-on whose extensions' run requirements will be used * @return a {@code String} representing the running issue, {@code null} if none. * @see AddOn.AddOnRunRequirements#getExtensionRequirements() */ public static List getExtensionsRunningIssues(AddOn.AddOnRunRequirements requirements) { if (!requirements.hasExtensionsWithRunningIssues()) { return new ArrayList<>(0); } List issues = new ArrayList<>(10); for (AddOn.ExtensionRunRequirements extReqs : requirements.getExtensionRequirements()) { issues.addAll(getRunningIssues(extReqs)); } return issues; } /** * Returns the textual representation of the Java version issue that prevents the add-on or extension from being run, if * any. *

* The message is not internationalised, should be used only for logging and non UI uses. * * @param requirements the run requirements of the add-on or extension * @return a {@code String} representing the running issue, {@code null} if none. */ public static String getJavaVersionIssue(AddOn.BaseRunRequirements requirements) { if (!requirements.isNewerJavaVersionRequired()) { return null; } if (requirements.getAddOn() != requirements.getAddOnMinimumJavaVersion()) { return MessageFormat.format( "Minimum Java version: {0} (\"{1}\" add-on)", requirements.getMinimumJavaVersion(), requirements.getAddOnMinimumJavaVersion().getName()); } return MessageFormat.format("Minimum Java version: {0}", requirements.getMinimumJavaVersion()); } /** * Returns the textual representation of the issue that prevents the add-on or extension from being run, if any. *

* The messages are not internationalised, should be used only for logging and non UI uses. * * @param requirements the run requirements of the add-on or extension * @return a {@code String} representing the running issue, {@code null} if none. */ public static String getDependencyIssue(AddOn.BaseRunRequirements requirements) { if (!requirements.hasDependencyIssue()) { return null; } List issueDetails = requirements.getDependencyIssueDetails(); switch (requirements.getDependencyIssue()) { case CYCLIC: return "Cyclic dependency with: " + issueDetails.get(0); case OLDER_VERSION: return "Older version still installed: " + issueDetails.get(0); case MISSING: String addOnId = (String) issueDetails.get(0); return MessageFormat.format("Add-On with ID \"{0}\"", addOnId); case PACKAGE_VERSION_NOT_BEFORE: AddOn addOn = (AddOn) issueDetails.get(0); return MessageFormat.format( "Add-on \"{0}\" with version not before {1} (found version {2})", addOn.getName(), issueDetails.get(1), Integer.valueOf(addOn.getFileVersion())); case PACKAGE_VERSION_NOT_FROM: addOn = (AddOn) issueDetails.get(0); return MessageFormat.format( "Add-on \"{0}\" with version not after {1} (found version {2})", addOn.getName(), issueDetails.get(1), Integer.valueOf(addOn.getFileVersion())); case VERSION: addOn = (AddOn) issueDetails.get(0); if (addOn.getVersion() == null) { return MessageFormat.format( "Add-on \"{0}\" with semantic version >= {1} (found no semantic version)", addOn.getName(), issueDetails.get(1)); } return MessageFormat.format( "Add-on \"{0}\" with semantic version >= {1} (found version {2})", addOn.getName(), issueDetails.get(1), addOn.getVersion()); default: LOGGER.warn("Failed to handle dependency issue with name \"" + requirements.getDependencyIssue().name() + "\" and details: " + issueDetails); return null; } } /** * Interface to search for add-ons with a given id. *

* Used to search for missing add-ons as reported by run requirements of an add-on. * * @see AddOn.BaseRunRequirements.DependencyIssue#MISSING */ public static interface AddOnSearcher { /** * Returns an add-on with the given id, if none is found returns {@code null}. * * @param id the id of the add-on * @return the add-on, or {@code null} if not found */ AddOn searchAddOn(String id); } }