diff --git a/zap/src/main/java/org/parosproxy/paros/core/scanner/AbstractPlugin.java b/zap/src/main/java/org/parosproxy/paros/core/scanner/AbstractPlugin.java index c6d82fe9291..f41f077e408 100644 --- a/zap/src/main/java/org/parosproxy/paros/core/scanner/AbstractPlugin.java +++ b/zap/src/main/java/org/parosproxy/paros/core/scanner/AbstractPlugin.java @@ -70,6 +70,8 @@ // ZAP: 2020/11/17 Use new TechSet#getAllTech(). // ZAP: 2020/11/26 Use Log4j2 getLogger() and deprecate Log4j1.x. // ZAP: 2021/07/20 Correct message updated with the scan rule ID header (Issue 6689). +// ZAP: 2022/01/04 Process notifications also on exception during sendAndReceive (Issue +// 7004). package org.parosproxy.paros.core.scanner; import java.io.IOException; @@ -94,6 +96,7 @@ import org.parosproxy.paros.network.HttpStatusCode; import org.zaproxy.zap.control.AddOn; import org.zaproxy.zap.extension.anticsrf.ExtensionAntiCSRF; +import org.zaproxy.zap.extension.ascan.ScannerTaskResult; import org.zaproxy.zap.extension.custompages.CustomPage; import org.zaproxy.zap.model.Tech; import org.zaproxy.zap.model.TechSet; @@ -309,16 +312,25 @@ protected void sendAndReceive( // ZAP: Runs the "beforeScan" methods of any ScannerHooks parent.performScannerHookBeforeScan(message, this); - if (isFollowRedirect) { - parent.getHttpSender().sendAndReceive(message, getParent().getRedirectRequestConfig()); - } else { - parent.getHttpSender().sendAndReceive(message, false); + try { + if (isFollowRedirect) { + parent.getHttpSender() + .sendAndReceive(message, getParent().getRedirectRequestConfig()); + } else { + parent.getHttpSender().sendAndReceive(message, false); + } + } catch (IOException e) { + message.setErrorResponse(e); + // ZAP: Notify parent + parent.notifyNewMessage(this, new ScannerTaskResult(message, e.getLocalizedMessage())); + return; } // ZAP: Notify parent - parent.notifyNewMessage(this, message); + parent.notifyNewMessage(this, new ScannerTaskResult(message)); - // ZAP: Set the history reference back and run the "afterScan" methods of any ScannerHooks + // ZAP: Set the history reference back and run the "afterScan" methods of any + // ScannerHooks parent.performScannerHookAfterScan(message, this); } diff --git a/zap/src/main/java/org/parosproxy/paros/core/scanner/Analyser.java b/zap/src/main/java/org/parosproxy/paros/core/scanner/Analyser.java index 6a3e0d7bd0e..a851ba6ee07 100644 --- a/zap/src/main/java/org/parosproxy/paros/core/scanner/Analyser.java +++ b/zap/src/main/java/org/parosproxy/paros/core/scanner/Analyser.java @@ -43,6 +43,7 @@ // ZAP: 2019/06/05 Normalise format/style. // ZAP: 2019/07/26 Remove null check in sendAndReceive(HttpMessage). (LGTM Issue) // ZAP: 2020/11/26 Use Log4j 2 classes for logging. +// ZAP: 2022/01/04 Use changed ScannerListener interface package org.parosproxy.paros.core.scanner; import java.io.IOException; @@ -63,6 +64,7 @@ import org.parosproxy.paros.network.HttpMessage; import org.parosproxy.paros.network.HttpSender; import org.parosproxy.paros.network.HttpStatusCode; +import org.zaproxy.zap.extension.ascan.ScannerTaskResult; import org.zaproxy.zap.model.StructuralNode; public class Analyser { @@ -519,7 +521,7 @@ private void sendAndReceive(HttpMessage msg) throws HttpException, IOException { httpSender.sendAndReceive(msg, parent.getRedirectRequestConfig()); requestCount++; - parent.notifyNewMessage(msg); + parent.notifyNewMessage(new ScannerTaskResult(msg)); } public int getDelayInMs() { diff --git a/zap/src/main/java/org/parosproxy/paros/core/scanner/HostProcess.java b/zap/src/main/java/org/parosproxy/paros/core/scanner/HostProcess.java index c832455fdbd..eba9c098773 100644 --- a/zap/src/main/java/org/parosproxy/paros/core/scanner/HostProcess.java +++ b/zap/src/main/java/org/parosproxy/paros/core/scanner/HostProcess.java @@ -99,6 +99,7 @@ // ZAP: 2020/11/26 Use Log4j 2 classes for logging. // ZAP: 2021/09/14 No longer force single threading if Anti CSRF handling turned on. // ZAP: 2021/09/30 Pass plugin to PluginStats instead of just the name. +// ZAP: 2022/01/04 Use changed ScannerListener interface package org.parosproxy.paros.core.scanner; import java.io.IOException; @@ -126,6 +127,7 @@ import org.parosproxy.paros.network.HttpSender; import org.zaproxy.zap.extension.alert.ExtensionAlert; import org.zaproxy.zap.extension.ascan.ScanPolicy; +import org.zaproxy.zap.extension.ascan.ScannerTaskResult; import org.zaproxy.zap.extension.ascan.filters.FilterResult; import org.zaproxy.zap.extension.ascan.filters.ScanFilter; import org.zaproxy.zap.extension.custompages.CustomPage; @@ -646,7 +648,7 @@ private boolean scanMessage(Plugin plugin, int messageId) { private boolean obtainResponse(HistoryReference hRef, HttpMessage message) { try { getHttpSender().sendAndReceive(message); - notifyNewMessage(message); + notifyNewMessage(new ScannerTaskResult(message)); requestCount++; return true; } catch (IOException e) { @@ -839,9 +841,11 @@ private void notifyHostComplete() { * * @param msg the new HTTP message * @since 1.2.0 + * @deprecated (2.12.0) Use {@link #notifyNewMessage(ScannerTaskResult)} */ + @Deprecated public void notifyNewMessage(HttpMessage msg) { - parentScanner.notifyNewMessage(msg); + notifyNewMessage(new ScannerTaskResult(msg)); } /** @@ -852,9 +856,37 @@ public void notifyNewMessage(HttpMessage msg) { * @throws IllegalArgumentException if the given {@code plugin} is {@code null}. * @since 2.5.0 * @see #notifyNewMessage(Plugin) + * @deprecated (2.12.0) Use {@link #notifyNewMessage(Plugin, ScannerTaskResult)} */ + @Deprecated public void notifyNewMessage(Plugin plugin, HttpMessage message) { - parentScanner.notifyNewMessage(message); + notifyNewMessage(plugin, new ScannerTaskResult(message)); + } + + /** + * Notifies interested parties that a new message was sent (and received). + * + *

{@link Plugin Plugins} should call {@link #notifyNewMessage(Plugin)} or {@link + * #notifyNewMessage(Plugin, ScannerTaskResult)}, instead. + * + * @param scannerTaskResult contains the new HTTP message + * @since 1.2.0 + */ + public void notifyNewMessage(ScannerTaskResult scannerTaskResult) { + parentScanner.notifyNewMessage(scannerTaskResult); + } + + /** + * Notifies that the given {@code plugin} sent (and received) the given HTTP message. + * + * @param plugin the plugin that sent the message + * @param scannerTaskResult contains the message sent + * @throws IllegalArgumentException if the given {@code plugin} is {@code null}. + * @since 2.5.0 + * @see #notifyNewMessage(Plugin) + */ + public void notifyNewMessage(Plugin plugin, ScannerTaskResult scannerTaskResult) { + parentScanner.notifyNewMessage(scannerTaskResult); notifyNewMessage(plugin); } @@ -867,7 +899,7 @@ public void notifyNewMessage(Plugin plugin, HttpMessage message) { * @param plugin the plugin that sent a non-HTTP message * @throws IllegalArgumentException if the given parameter is {@code null}. * @since 2.5.0 - * @see #notifyNewMessage(Plugin, HttpMessage) + * @see #notifyNewMessage(Plugin, ScannerTaskResult) */ public void notifyNewMessage(Plugin plugin) { if (plugin == null) { diff --git a/zap/src/main/java/org/parosproxy/paros/core/scanner/Scanner.java b/zap/src/main/java/org/parosproxy/paros/core/scanner/Scanner.java index 384fd051a17..e24e464c154 100644 --- a/zap/src/main/java/org/parosproxy/paros/core/scanner/Scanner.java +++ b/zap/src/main/java/org/parosproxy/paros/core/scanner/Scanner.java @@ -52,6 +52,7 @@ // ZAP: 2020/11/17 Use new TechSet#getAllTech(). // ZAP: 2020/11/26 Use Log4j 2 classes for logging. // ZAP: 2021/05/14 Remove redundant type arguments. +// ZAP: 2022/01/04 Use changed ScannerListener interface package org.parosproxy.paros.core.scanner; import java.security.InvalidParameterException; @@ -79,6 +80,7 @@ import org.parosproxy.paros.network.HttpMessage; import org.zaproxy.zap.extension.ascan.ActiveScanEventPublisher; import org.zaproxy.zap.extension.ascan.ScanPolicy; +import org.zaproxy.zap.extension.ascan.ScannerTaskResult; import org.zaproxy.zap.extension.ascan.filters.ScanFilter; import org.zaproxy.zap.extension.ruleconfig.RuleConfigParam; import org.zaproxy.zap.extension.script.ScriptCollection; @@ -455,10 +457,16 @@ public boolean isPaused() { return pause; } + /** @deprecated (2.12.0) Use {@link #notifyNewMessage(ScannerTaskResult)} */ + @Deprecated public void notifyNewMessage(HttpMessage msg) { + notifyNewMessage(new ScannerTaskResult(msg)); + } + + public void notifyNewMessage(ScannerTaskResult scannerTaskResult) { for (int i = 0; i < listenerList.size(); i++) { ScannerListener listener = listenerList.get(i); - listener.notifyNewMessage(msg); + listener.notifyNewTaskResult(scannerTaskResult); } } diff --git a/zap/src/main/java/org/parosproxy/paros/core/scanner/ScannerListener.java b/zap/src/main/java/org/parosproxy/paros/core/scanner/ScannerListener.java index 324b4b50364..f8f2e10fdaa 100644 --- a/zap/src/main/java/org/parosproxy/paros/core/scanner/ScannerListener.java +++ b/zap/src/main/java/org/parosproxy/paros/core/scanner/ScannerListener.java @@ -25,9 +25,11 @@ // ZAP: 2019/06/05 Normalise format/style. // ZAP: 2019/12/10 Issue 5278: Adding filtered messages to active scan panel. // ZAP: 2021/05/14 Remove empty statement. +// ZAP: 2022/01/14 deprecated notifyNewMessage and added notifyNewTaskResult package org.parosproxy.paros.core.scanner; import org.parosproxy.paros.network.HttpMessage; +import org.zaproxy.zap.extension.ascan.ScannerTaskResult; public interface ScannerListener { @@ -41,8 +43,13 @@ public interface ScannerListener { void alertFound(Alert alert); - // ZAP: Added notifyNewMessage - void notifyNewMessage(HttpMessage msg); + /** @deprecated (2.12.0) Use {@link #notifyNewTaskResult(ScannerTaskResult)} */ + @Deprecated + default void notifyNewMessage(HttpMessage msg) {} + + default void notifyNewTaskResult(ScannerTaskResult scannerTaskResult) { + notifyNewMessage(scannerTaskResult.getHttpMessage()); + } /** * Added to notify reason for filtering message from scanning. diff --git a/zap/src/main/java/org/parosproxy/paros/network/HttpMessage.java b/zap/src/main/java/org/parosproxy/paros/network/HttpMessage.java index 44b4c02eb22..fe052f9e8de 100644 --- a/zap/src/main/java/org/parosproxy/paros/network/HttpMessage.java +++ b/zap/src/main/java/org/parosproxy/paros/network/HttpMessage.java @@ -60,9 +60,12 @@ // ZAP: 2021/04/01 Detect WebSocket upgrade messages having multiple Connection directives // ZAP: 2021/05/11 Fixed conversion of Request Method to/from CONNECT // ZAP: 2021/05/14 Add missing override annotation. +// ZAP: 2022/01/14 Added setErrorResponse method + package org.parosproxy.paros.network; import java.net.HttpCookie; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -74,11 +77,14 @@ import java.util.SortedSet; import java.util.TreeSet; import java.util.Vector; +import javax.net.ssl.SSLException; import org.apache.commons.httpclient.URI; import org.apache.commons.httpclient.URIException; import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.exception.ExceptionUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.parosproxy.paros.Constant; import org.parosproxy.paros.model.HistoryReference; import org.parosproxy.paros.model.Model; import org.zaproxy.zap.eventBus.Event; @@ -1239,4 +1245,53 @@ public Map toEventData() { public String getType() { return MESSAGE_TYPE; } + + public void setErrorResponse(Exception cause) { + StringBuilder strBuilder = new StringBuilder(250); + if (cause instanceof SSLException) { + strBuilder.append(Constant.messages.getString("network.ssl.error.connect")); + strBuilder.append(this.getRequestHeader().getURI().toString()).append('\n'); + strBuilder + .append(Constant.messages.getString("network.ssl.error.exception")) + .append(cause.getMessage()) + .append('\n'); + strBuilder + .append(Constant.messages.getString("network.ssl.error.exception.rootcause")) + .append(ExceptionUtils.getRootCauseMessage(cause)) + .append('\n'); + strBuilder.append( + Constant.messages.getString( + "network.ssl.error.help", + Constant.messages.getString("network.ssl.error.help.url"))); + + strBuilder.append("\n\nStack Trace:\n"); + for (String stackTraceFrame : ExceptionUtils.getRootCauseStackTrace(cause)) { + strBuilder.append(stackTraceFrame).append('\n'); + } + } else { + strBuilder + .append(cause.getClass().getName()) + .append(": ") + .append(cause.getLocalizedMessage()) + .append("\n\nStack Trace:\n"); + for (String stackTraceFrame : ExceptionUtils.getRootCauseStackTrace(cause)) { + strBuilder.append(stackTraceFrame).append('\n'); + } + } + + String message = strBuilder.toString(); + + HttpResponseHeader responseHeader; + try { + responseHeader = new HttpResponseHeader("HTTP/1.1 400 ZAP IO Error"); + responseHeader.setHeader(HttpHeader.CONTENT_TYPE, "text/plain; charset=UTF-8"); + responseHeader.setHeader( + HttpHeader.CONTENT_LENGTH, + Integer.toString(message.getBytes(StandardCharsets.UTF_8).length)); + this.setResponseHeader(responseHeader); + this.setResponseBody(message); + } catch (HttpMalformedHeaderException e) { + log.error("Failed to create error response:", e); + } + } } diff --git a/zap/src/main/java/org/zaproxy/zap/extension/ascan/ActiveScan.java b/zap/src/main/java/org/zaproxy/zap/extension/ascan/ActiveScan.java index da56e84b23d..cdd7cdbb9b1 100644 --- a/zap/src/main/java/org/zaproxy/zap/extension/ascan/ActiveScan.java +++ b/zap/src/main/java/org/zaproxy/zap/extension/ascan/ActiveScan.java @@ -75,6 +75,7 @@ public static enum State { private int maxResultsToList = 0; private final List hRefs = Collections.synchronizedList(new ArrayList<>()); + private final List hRefsWithError = Collections.synchronizedList(new ArrayList<>()); private final List alerts = Collections.synchronizedList(new ArrayList<>()); private ScheduledExecutorService scheduler; @@ -273,7 +274,8 @@ public ActiveScanTableModel getMessagesTableModel() { } @Override - public void notifyNewMessage(final HttpMessage msg) { + public void notifyNewTaskResult(final ScannerTaskResult scannerTaskResult) { + HttpMessage msg = scannerTaskResult.getHttpMessage(); HistoryReference hRef = msg.getHistoryRef(); if (hRef == null) { try { @@ -283,12 +285,12 @@ public void notifyNewMessage(final HttpMessage msg) { HistoryReference.TYPE_SCANNER_TEMPORARY, msg); msg.setHistoryRef(null); - hRefs.add(hRef.getHistoryId()); + addHref(hRef.getHistoryId(), scannerTaskResult.isProcessed()); } catch (HttpMalformedHeaderException | DatabaseException e) { log.error(e.getMessage(), e); } } else { - hRefs.add(hRef.getHistoryId()); + addHref(hRef.getHistoryId(), scannerTaskResult.isProcessed()); } this.rcTotals.incResponseCodeCount(msg.getResponseHeader().getStatusCode()); @@ -299,17 +301,26 @@ public void notifyNewMessage(final HttpMessage msg) { if (this.rcTotals.getTotal() > this.maxResultsToList) { removeFirstHistoryReferenceInEdt(); } - addHistoryReferenceInEdt(hRef); + addHistoryReferenceInEdt(hRef, scannerTaskResult); } } - private void addHistoryReferenceInEdt(final HistoryReference hRef) { + private void addHref(int historyId, boolean noError){ + if(noError){ + hRefs.add(historyId); + } else{ + hRefsWithError.add(historyId); + } + } + + private void addHistoryReferenceInEdt( + final HistoryReference hRef, ScannerTaskResult scannerTaskResult) { EventQueue.invokeLater( new Runnable() { @Override public void run() { - messagesTableModel.addHistoryReference(hRef); + messagesTableModel.addEntry(hRef, scannerTaskResult); } }); } @@ -374,6 +385,21 @@ public List getMessagesIds() { return hRefs; } + /** + * Returns the IDs of all messages sent/created during the scan which threw an error (e.g. IOException). The message must be recreated + * with a HistoryReference. + * + *

Note: Iterations must be {@code synchronized} on returned object. Failing + * to do so might result in {@code ConcurrentModificationException}. + * + * @return the IDs of all the messages sent/created during the scan which threw an error (e.g. IOException) + * @see HistoryReference + * @see ConcurrentModificationException + */ + public List getMessagesIdsWithError() { + return hRefsWithError; + } + /** * Returns the IDs of all alerts raised during the scan. * diff --git a/zap/src/main/java/org/zaproxy/zap/extension/ascan/ActiveScanAPI.java b/zap/src/main/java/org/zaproxy/zap/extension/ascan/ActiveScanAPI.java index 7f06d990aa3..85b6ff07ac7 100644 --- a/zap/src/main/java/org/zaproxy/zap/extension/ascan/ActiveScanAPI.java +++ b/zap/src/main/java/org/zaproxy/zap/extension/ascan/ActiveScanAPI.java @@ -112,6 +112,7 @@ public class ActiveScanAPI extends ApiImplementor { private static final String VIEW_STATUS = "status"; private static final String VIEW_SCANS = "scans"; private static final String VIEW_MESSAGES_IDS = "messagesIds"; + private static final String VIEW_MESSAGES_IDS_WITH_ERROR = "messagesIdsWithError"; private static final String VIEW_ALERTS_IDS = "alertsIds"; private static final String VIEW_EXCLUDED_FROM_SCAN = "excludedFromScan"; private static final String VIEW_SCANNERS = "scanners"; @@ -261,6 +262,7 @@ public ActiveScanAPI(ExtensionActiveScan controller) { this.addApiView(new ApiView(VIEW_STATUS, null, new String[] {PARAM_SCAN_ID})); this.addApiView(new ApiView(VIEW_SCAN_PROGRESS, null, new String[] {PARAM_SCAN_ID})); this.addApiView(new ApiView(VIEW_MESSAGES_IDS, new String[] {PARAM_SCAN_ID})); + this.addApiView(new ApiView(VIEW_MESSAGES_IDS_WITH_ERROR, new String[] {PARAM_SCAN_ID})); this.addApiView(new ApiView(VIEW_ALERTS_IDS, new String[] {PARAM_SCAN_ID})); this.addApiView(new ApiView(VIEW_SCANS)); this.addApiView(new ApiView(VIEW_SCAN_POLICY_NAMES)); @@ -1038,6 +1040,16 @@ public ApiResponse handleApiView(String name, JSONObject params) throws ApiExcep } result = resultList; break; + case VIEW_MESSAGES_IDS_WITH_ERROR: + resultList = new ApiResponseList(name); + activeScan = getActiveScan(params); + synchronized (activeScan.getMessagesIdsWithError()) { + for (Integer id : activeScan.getMessagesIdsWithError()) { + resultList.addItem(new ApiResponseElement("id", id.toString())); + } + } + result = resultList; + break; case VIEW_ALERTS_IDS: resultList = new ApiResponseList(name); activeScan = getActiveScan(params); diff --git a/zap/src/main/java/org/zaproxy/zap/extension/ascan/ActiveScanPanel.java b/zap/src/main/java/org/zaproxy/zap/extension/ascan/ActiveScanPanel.java index 5fea48a5a90..61bd53d6891 100644 --- a/zap/src/main/java/org/zaproxy/zap/extension/ascan/ActiveScanPanel.java +++ b/zap/src/main/java/org/zaproxy/zap/extension/ascan/ActiveScanPanel.java @@ -39,7 +39,6 @@ import org.parosproxy.paros.core.scanner.Alert; import org.parosproxy.paros.core.scanner.HostProcess; import org.parosproxy.paros.core.scanner.ScannerListener; -import org.parosproxy.paros.network.HttpMessage; import org.parosproxy.paros.view.View; import org.zaproxy.zap.model.ScanController; import org.zaproxy.zap.model.ScanListenner2; @@ -75,7 +74,7 @@ public class ActiveScanPanel extends ScanPanel2 { + + private final boolean successful; + private final String label; + + public ActiveScanProcessedCellItem(boolean successful, String label) { + this.successful = successful; + this.label = label; + } + + public boolean isSuccessful() { + return successful; + } + + public String getLabel() { + return label; + } + + @Override + public String toString() { + return label; + } + + @Override + public int hashCode() { + return 31 * (successful ? 1231 : 1237); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + ActiveScanProcessedCellItem other = (ActiveScanProcessedCellItem) obj; + if (successful != other.successful) { + return false; + } + return true; + } + + @Override + public int compareTo(ActiveScanProcessedCellItem other) { + if (other == null) { + return 1; + } + if (successful && !other.successful) { + return 1; + } else if (!successful && other.successful) { + return -1; + } + return label.compareTo(other.label); + } +} diff --git a/zap/src/main/java/org/zaproxy/zap/extension/ascan/ActiveScanTable.java b/zap/src/main/java/org/zaproxy/zap/extension/ascan/ActiveScanTable.java new file mode 100644 index 00000000000..88573fcc042 --- /dev/null +++ b/zap/src/main/java/org/zaproxy/zap/extension/ascan/ActiveScanTable.java @@ -0,0 +1,113 @@ +/* + * Zed Attack Proxy (ZAP) and its related class files. + * + * ZAP is an HTTP/HTTPS proxy for assessing web application security. + * + * Copyright 2022 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.extension.ascan; + +import java.awt.Component; +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JLabel; +import org.jdesktop.swingx.decorator.AbstractHighlighter; +import org.jdesktop.swingx.decorator.ComponentAdapter; +import org.jdesktop.swingx.renderer.DefaultTableRenderer; +import org.jdesktop.swingx.renderer.IconAware; +import org.jdesktop.swingx.renderer.IconValues; +import org.jdesktop.swingx.renderer.MappedValue; +import org.jdesktop.swingx.renderer.StringValues; +import org.zaproxy.zap.view.table.HistoryReferencesTable; + +public class ActiveScanTable extends HistoryReferencesTable { + + private static final long serialVersionUID = 1L; + + public ActiveScanTable(ActiveScanTableModel model) { + super(model); + + getColumnExt(0) + .setCellRenderer( + new DefaultTableRenderer( + new MappedValue(StringValues.EMPTY, IconValues.NONE), + JLabel.CENTER)); + + getColumnExt(0).setHighlighters(new ProcessedCellItemIconHighlighter(0)); + } + + /** + * A {@link org.jdesktop.swingx.decorator.Highlighter Highlighter} for a column that indicates, + * using icons and text, whether or not an entry was processed, that is, is or not in scope. + * + *

The expected type/class of the cell values is {@code ProcessedCellItem}. + */ + private static class ProcessedCellItemIconHighlighter extends AbstractHighlighter { + + /** The icon that indicates the entry was processed. */ + private static final ImageIcon PROCESSED_ICON = + new ImageIcon(ActiveScanTable.class.getResource("/resource/icon/16/152.png")); + + /** The icon that indicates the entry was not processed. */ + private static final ImageIcon NOT_PROCESSED_ICON = + new ImageIcon(ActiveScanTable.class.getResource("/resource/icon/16/149.png")); + + private final int columnIndex; + + public ProcessedCellItemIconHighlighter(final int columnIndex) { + this.columnIndex = columnIndex; + } + + @Override + protected Component doHighlight(Component component, ComponentAdapter adapter) { + ActiveScanProcessedCellItem cell = + (ActiveScanProcessedCellItem) adapter.getValue(columnIndex); + + boolean processed = cell.isSuccessful(); + Icon icon = getProcessedIcon(processed); + if (component instanceof IconAware) { + ((IconAware) component).setIcon(icon); + } else if (component instanceof JLabel) { + ((JLabel) component).setIcon(icon); + } + + if (component instanceof JLabel) { + ((JLabel) component).setText(processed ? "" : cell.getLabel()); + } + + return component; + } + + private static Icon getProcessedIcon(final boolean processed) { + return processed ? PROCESSED_ICON : NOT_PROCESSED_ICON; + } + + /** + * {@inheritDoc} + * + *

Overridden to return true if the component is of type IconAware or of type JLabel, + * false otherwise. + * + *

Note: special casing JLabel is for backward compatibility - application highlighting + * code which doesn't use the Swingx renderers would stop working otherwise. + */ + // Method/JavaDoc copied from + // org.jdesktop.swingx.decorator.IconHighlighter#canHighlight(Component, ComponentAdapter) + @Override + protected boolean canHighlight(final Component component, final ComponentAdapter adapter) { + return component instanceof IconAware || component instanceof JLabel; + } + } +} diff --git a/zap/src/main/java/org/zaproxy/zap/extension/ascan/ActiveScanTableEntry.java b/zap/src/main/java/org/zaproxy/zap/extension/ascan/ActiveScanTableEntry.java new file mode 100644 index 00000000000..284f6611fae --- /dev/null +++ b/zap/src/main/java/org/zaproxy/zap/extension/ascan/ActiveScanTableEntry.java @@ -0,0 +1,38 @@ +/* + * Zed Attack Proxy (ZAP) and its related class files. + * + * ZAP is an HTTP/HTTPS proxy for assessing web application security. + * + * Copyright 2022 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.extension.ascan; + +import org.parosproxy.paros.model.HistoryReference; +import org.zaproxy.zap.view.table.DefaultHistoryReferencesTableEntry; + +public class ActiveScanTableEntry extends DefaultHistoryReferencesTableEntry { + + private ActiveScanProcessedCellItem processedCellItem; + + public ActiveScanTableEntry( + HistoryReference historyReference, ActiveScanProcessedCellItem processedCellItem) { + super(historyReference, ActiveScanTableModel.COLUMNS); + this.processedCellItem = processedCellItem; + } + + public ActiveScanProcessedCellItem getProcessedCellItem() { + return processedCellItem; + } +} diff --git a/zap/src/main/java/org/zaproxy/zap/extension/ascan/ActiveScanTableModel.java b/zap/src/main/java/org/zaproxy/zap/extension/ascan/ActiveScanTableModel.java index f149caf989f..3ae810b5eb6 100644 --- a/zap/src/main/java/org/zaproxy/zap/extension/ascan/ActiveScanTableModel.java +++ b/zap/src/main/java/org/zaproxy/zap/extension/ascan/ActiveScanTableModel.java @@ -19,25 +19,82 @@ */ package org.zaproxy.zap.extension.ascan; -import org.zaproxy.zap.view.table.DefaultHistoryReferencesTableModel; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.parosproxy.paros.Constant; +import org.parosproxy.paros.model.HistoryReference; +import org.zaproxy.zap.view.table.CustomColumn; +import org.zaproxy.zap.view.table.DefaultCustomColumnHistoryReferencesTableModel; -public class ActiveScanTableModel extends DefaultHistoryReferencesTableModel { +public class ActiveScanTableModel + extends DefaultCustomColumnHistoryReferencesTableModel { private static final long serialVersionUID = 5732679524771190690L; + private static final ActiveScanProcessedCellItem SUCCESSFULLY_PROCESSED_CELL_ITEM; + private Map cacheProcessedCellItems; + public static final Column[] COLUMNS = + new Column[] { + Column.CUSTOM, + Column.HREF_ID, + Column.REQUEST_TIMESTAMP, + Column.RESPONSE_TIMESTAMP, + Column.METHOD, + Column.URL, + Column.STATUS_CODE, + Column.STATUS_REASON, + Column.RTT, + Column.SIZE_RESPONSE_HEADER, + Column.SIZE_RESPONSE_BODY + }; + + private static final List> CUSTOM_COLUMNS = + Arrays.asList(createProcessedColumn()); + + static { + SUCCESSFULLY_PROCESSED_CELL_ITEM = + new ActiveScanProcessedCellItem( + true, + Constant.messages.getString( + "ascan.panel.tab.scannedMessages.column.processed.successfully")); + } public ActiveScanTableModel() { - super( - new Column[] { - Column.HREF_ID, - Column.REQUEST_TIMESTAMP, - Column.RESPONSE_TIMESTAMP, - Column.METHOD, - Column.URL, - Column.STATUS_CODE, - Column.STATUS_REASON, - Column.RTT, - Column.SIZE_RESPONSE_HEADER, - Column.SIZE_RESPONSE_BODY - }); + super(COLUMNS, CUSTOM_COLUMNS, ActiveScanTableEntry.class); + cacheProcessedCellItems = new HashMap<>(); + } + + private static CustomColumn createProcessedColumn() { + return new CustomColumn( + String.class, + Constant.messages.getString("ascan.panel.tab.scannedMessages.column.processed")) { + + @Override + public Object getValue(ActiveScanTableEntry model) { + return model.getProcessedCellItem(); + } + }; + } + + public void addEntry(HistoryReference hRef, ScannerTaskResult scannerTaskResult) { + addEntry(new ActiveScanTableEntry(hRef, getProcessedCellItem(scannerTaskResult))); + } + + private ActiveScanProcessedCellItem getProcessedCellItem(ScannerTaskResult scannerTaskResult) { + if (scannerTaskResult.isProcessed()) { + return SUCCESSFULLY_PROCESSED_CELL_ITEM; + } + ActiveScanProcessedCellItem processedCellItem = + cacheProcessedCellItems.get(scannerTaskResult.getReasonNotProcessed()); + if (processedCellItem == null) { + processedCellItem = + new ActiveScanProcessedCellItem( + scannerTaskResult.isProcessed(), + scannerTaskResult.getReasonNotProcessed()); + cacheProcessedCellItems.put( + scannerTaskResult.getReasonNotProcessed(), processedCellItem); + } + return processedCellItem; } } diff --git a/zap/src/main/java/org/zaproxy/zap/extension/ascan/AttackModeScanner.java b/zap/src/main/java/org/zaproxy/zap/extension/ascan/AttackModeScanner.java index aafaa8c6e8e..4a9a0f1dd12 100644 --- a/zap/src/main/java/org/zaproxy/zap/extension/ascan/AttackModeScanner.java +++ b/zap/src/main/java/org/zaproxy/zap/extension/ascan/AttackModeScanner.java @@ -38,7 +38,6 @@ import org.parosproxy.paros.model.Session; import org.parosproxy.paros.model.SiteMapEventPublisher; import org.parosproxy.paros.model.SiteNode; -import org.parosproxy.paros.network.HttpMessage; import org.parosproxy.paros.view.View; import org.zaproxy.zap.ZAP; import org.zaproxy.zap.eventBus.Event; @@ -381,8 +380,8 @@ public void alertFound(Alert alert) { } @Override - public void notifyNewMessage(HttpMessage msg) { - ascanWrapper.notifyNewMessage(msg); + public void notifyNewTaskResult(ScannerTaskResult scannerTaskResult) { + ascanWrapper.notifyNewMessage(scannerTaskResult); } public void shutdown() { diff --git a/zap/src/main/java/org/zaproxy/zap/extension/ascan/ScannerTaskResult.java b/zap/src/main/java/org/zaproxy/zap/extension/ascan/ScannerTaskResult.java new file mode 100644 index 00000000000..bbb4d843982 --- /dev/null +++ b/zap/src/main/java/org/zaproxy/zap/extension/ascan/ScannerTaskResult.java @@ -0,0 +1,64 @@ +/* + * Zed Attack Proxy (ZAP) and its related class files. + * + * ZAP is an HTTP/HTTPS proxy for assessing web application security. + * + * Copyright 2022 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.extension.ascan; + +import org.parosproxy.paros.network.HttpMessage; + +/** + * Contains the message and processing details. + * + * @since 2.12.0 + */ +public class ScannerTaskResult { + + private final HttpMessage httpMessage; + private final boolean processed; + private final String reasonNotProcessed; + + public ScannerTaskResult(HttpMessage httpMessage) { + this(httpMessage, true, ""); + } + + public ScannerTaskResult(HttpMessage httpMessage, String reasonNotProcessed) { + this(httpMessage, false, reasonNotProcessed); + } + + private ScannerTaskResult( + HttpMessage httpMessage, boolean processed, String reasonNotProcessed) { + if (reasonNotProcessed == null) { + throw new IllegalArgumentException("Parameter reason must not be null."); + } + this.httpMessage = httpMessage; + this.processed = processed; + this.reasonNotProcessed = reasonNotProcessed; + } + + public HttpMessage getHttpMessage() { + return httpMessage; + } + + public boolean isProcessed() { + return processed; + } + + public String getReasonNotProcessed() { + return reasonNotProcessed; + } +} diff --git a/zap/src/main/java/org/zaproxy/zap/extension/callback/ui/CustomColumn.java b/zap/src/main/java/org/zaproxy/zap/extension/callback/ui/CustomColumn.java index 48a1c216446..7481da82916 100644 --- a/zap/src/main/java/org/zaproxy/zap/extension/callback/ui/CustomColumn.java +++ b/zap/src/main/java/org/zaproxy/zap/extension/callback/ui/CustomColumn.java @@ -19,7 +19,7 @@ */ package org.zaproxy.zap.extension.callback.ui; -/** @deprecated (2.11.0) Superseded by the OAST add-on. */ +/** @deprecated (2.11.0) {@link org.zaproxy.zap.view.table.CustomColumn}. */ @Deprecated public abstract class CustomColumn { Class columnClass; diff --git a/zap/src/main/java/org/zaproxy/zap/extension/callback/ui/DefaultCustomColumnHistoryReferencesTableModel.java b/zap/src/main/java/org/zaproxy/zap/extension/callback/ui/DefaultCustomColumnHistoryReferencesTableModel.java index f8ab7903a3c..249fd077e67 100644 --- a/zap/src/main/java/org/zaproxy/zap/extension/callback/ui/DefaultCustomColumnHistoryReferencesTableModel.java +++ b/zap/src/main/java/org/zaproxy/zap/extension/callback/ui/DefaultCustomColumnHistoryReferencesTableModel.java @@ -25,7 +25,10 @@ import org.zaproxy.zap.view.table.DefaultHistoryReferencesTableEntry; import org.zaproxy.zap.view.table.DefaultHistoryReferencesTableModel; -/** @deprecated (2.11.0) Superseded by the OAST add-on. */ +/** + * @deprecated (2.11.0) Superseded by {@link + * org.zaproxy.zap.view.table.DefaultCustomColumnHistoryReferencesTableModel}. + */ @Deprecated public class DefaultCustomColumnHistoryReferencesTableModel< T extends DefaultHistoryReferencesTableEntry> diff --git a/zap/src/main/java/org/zaproxy/zap/spider/SpiderTask.java b/zap/src/main/java/org/zaproxy/zap/spider/SpiderTask.java index fd45ec4b1e8..8b59fd3f09d 100644 --- a/zap/src/main/java/org/zaproxy/zap/spider/SpiderTask.java +++ b/zap/src/main/java/org/zaproxy/zap/spider/SpiderTask.java @@ -24,16 +24,12 @@ import java.net.SocketException; import java.net.SocketTimeoutException; import java.net.UnknownHostException; -import java.nio.charset.StandardCharsets; import java.util.List; -import javax.net.ssl.SSLException; import net.htmlparser.jericho.Source; import org.apache.commons.httpclient.URI; import org.apache.commons.httpclient.URIException; -import org.apache.commons.lang.exception.ExceptionUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.parosproxy.paros.Constant; import org.parosproxy.paros.control.Control; import org.parosproxy.paros.db.DatabaseException; import org.parosproxy.paros.extension.history.ExtensionHistory; @@ -43,7 +39,6 @@ import org.parosproxy.paros.network.HttpMalformedHeaderException; import org.parosproxy.paros.network.HttpMessage; import org.parosproxy.paros.network.HttpRequestHeader; -import org.parosproxy.paros.network.HttpResponseHeader; import org.zaproxy.zap.spider.filters.ParseFilter; import org.zaproxy.zap.spider.filters.ParseFilter.FilterResult; import org.zaproxy.zap.spider.parser.SpiderParser; @@ -177,7 +172,7 @@ private void runImpl() { try { fetchResource(msg); } catch (Exception e) { - setErrorResponse(msg, e); + msg.setErrorResponse(e); parent.notifyListenersSpiderTaskResult( new SpiderTaskResult(msg, getSkippedMessage("ioerror"))); return; @@ -304,55 +299,6 @@ private void deleteHistoryReference() { } } - private void setErrorResponse(HttpMessage msg, Exception cause) { - StringBuilder strBuilder = new StringBuilder(250); - if (cause instanceof SSLException) { - strBuilder.append(Constant.messages.getString("network.ssl.error.connect")); - strBuilder.append(msg.getRequestHeader().getURI().toString()).append('\n'); - strBuilder - .append(Constant.messages.getString("network.ssl.error.exception")) - .append(cause.getMessage()) - .append('\n'); - strBuilder - .append(Constant.messages.getString("network.ssl.error.exception.rootcause")) - .append(ExceptionUtils.getRootCauseMessage(cause)) - .append('\n'); - strBuilder.append( - Constant.messages.getString( - "network.ssl.error.help", - Constant.messages.getString("network.ssl.error.help.url"))); - - strBuilder.append("\n\nStack Trace:\n"); - for (String stackTraceFrame : ExceptionUtils.getRootCauseStackTrace(cause)) { - strBuilder.append(stackTraceFrame).append('\n'); - } - } else { - strBuilder - .append(cause.getClass().getName()) - .append(": ") - .append(cause.getLocalizedMessage()) - .append("\n\nStack Trace:\n"); - for (String stackTraceFrame : ExceptionUtils.getRootCauseStackTrace(cause)) { - strBuilder.append(stackTraceFrame).append('\n'); - } - } - - String message = strBuilder.toString(); - - HttpResponseHeader responseHeader; - try { - responseHeader = new HttpResponseHeader("HTTP/1.1 400 ZAP IO Error"); - responseHeader.setHeader(HttpHeader.CONTENT_TYPE, "text/plain; charset=UTF-8"); - responseHeader.setHeader( - HttpHeader.CONTENT_LENGTH, - Integer.toString(message.getBytes(StandardCharsets.UTF_8).length)); - msg.setResponseHeader(responseHeader); - msg.setResponseBody(message); - } catch (HttpMalformedHeaderException e) { - log.error("Failed to create error response:", e); - } - } - /** * Process a resource, searching for links (uris) to other resources. * diff --git a/zap/src/main/java/org/zaproxy/zap/view/table/CustomColumn.java b/zap/src/main/java/org/zaproxy/zap/view/table/CustomColumn.java new file mode 100644 index 00000000000..cb0c581b8f1 --- /dev/null +++ b/zap/src/main/java/org/zaproxy/zap/view/table/CustomColumn.java @@ -0,0 +1,44 @@ +/* + * Zed Attack Proxy (ZAP) and its related class files. + * + * ZAP is an HTTP/HTTPS proxy for assessing web application security. + * + * Copyright 2022 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.view.table; + +public abstract class CustomColumn { + Class columnClass; + String name; + + public CustomColumn(Class columnClass, String name) { + this.columnClass = columnClass; + this.name = name; + } + + public Class getColumnClass() { + return columnClass; + } + + public String getName() { + return name; + } + + public abstract Object getValue(T model); + + public Object getPrototypeValue() { + return null; + } +} diff --git a/zap/src/main/java/org/zaproxy/zap/view/table/DefaultCustomColumnHistoryReferencesTableModel.java b/zap/src/main/java/org/zaproxy/zap/view/table/DefaultCustomColumnHistoryReferencesTableModel.java new file mode 100644 index 00000000000..03a6b23a693 --- /dev/null +++ b/zap/src/main/java/org/zaproxy/zap/view/table/DefaultCustomColumnHistoryReferencesTableModel.java @@ -0,0 +1,141 @@ +/* + * Zed Attack Proxy (ZAP) and its related class files. + * + * ZAP is an HTTP/HTTPS proxy for assessing web application security. + * + * Copyright 2022 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.view.table; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class DefaultCustomColumnHistoryReferencesTableModel< + T extends DefaultHistoryReferencesTableEntry> + extends DefaultHistoryReferencesTableModel { + + private static final long serialVersionUID = 1L; + private Map> customColumns; + private Class type; + + /** + * The class adds custom columns to the {@code DefaultHistoryReferencesTableModel}. + * + * @param columns Add the {@code Column.CUSTOM} at the desired position in the column list. + * @param customColumns Provide the implementations of the custom columns you passed to the + * {@code columns} parameter. When the count does not match then empty columns are created + * on that particular index. + */ + public DefaultCustomColumnHistoryReferencesTableModel( + final Column[] columns, final List> customColumns, Class type) { + super(columns); + this.type = type; + this.customColumns = createCustomColumnMap(columns, customColumns); + } + + private Map> createCustomColumnMap( + Column[] columns, List> customColumns) { + Map> customColumnMap = new HashMap<>(); + + int customColumnIndex = 0; + for (int i = 0; i < columns.length; i++) { + if (columns[i] == Column.CUSTOM) { + CustomColumn customColumn = + getCustomColumnIfExists(customColumns, customColumnIndex); + customColumnMap.put(i, customColumn); + customColumnIndex++; + } + } + + return customColumnMap; + } + + private CustomColumn getCustomColumnIfExists( + List> customColumns, Integer index) { + if (index < customColumns.size()) { + return customColumns.get(index); + } + return emptyColumn(); + } + + private CustomColumn emptyColumn() { + return new CustomColumn(String.class, "") { + + @Override + public Object getValue(T model) { + return ""; + } + }; + } + + private CustomColumn getCustomColumn(int columnIndex) { + return customColumns.get(columnIndex); + } + + @Override + public Class getColumnClass(int columnIndex) { + if (isCustomColumn(columnIndex)) { + return getCustomColumn(columnIndex).getColumnClass(); + } + + return super.getColumnClass(getColumn(columnIndex)); + } + + @Override + public String getColumnName(int columnIndex) { + if (isCustomColumn(columnIndex)) { + return getCustomColumn(columnIndex).getName(); + } + + return super.getColumnName(columnIndex); + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + if (isCustomColumn(columnIndex)) { + if (rowIndex >= getRowCount()) { + return null; + } + + DefaultHistoryReferencesTableEntry entry = getEntry(rowIndex); + return getCustomColumn(columnIndex).getValue(uncheckedCast(entry)); + } + + return super.getValueAt(rowIndex, columnIndex); + } + + @SuppressWarnings({"unchecked"}) + private T uncheckedCast(DefaultHistoryReferencesTableEntry entry) { + if (!type.isInstance(entry)) { + return null; + } + + try { + return (T) entry; + } catch (ClassCastException e) { + return null; + } + } + + @Override + public Object getPrototypeValue(int columnIndex) { + if (isCustomColumn(columnIndex)) { + return getCustomColumn(columnIndex).getPrototypeValue(); + } + + return super.getPrototypeValue(columnIndex); + } +} diff --git a/zap/src/main/resources/org/zaproxy/zap/resources/Messages.properties b/zap/src/main/resources/org/zaproxy/zap/resources/Messages.properties index 31cff469c40..00e1bb7bf12 100644 --- a/zap/src/main/resources/org/zaproxy/zap/resources/Messages.properties +++ b/zap/src/main/resources/org/zaproxy/zap/resources/Messages.properties @@ -395,7 +395,9 @@ ascan.api.view.attackModeQueue = ascan.api.view.excludedParams = Gets all the parameters that are excluded. For each parameter the following are shown: the name, the URL, and the parameter type. ascan.api.view.excludedParamTypes = Gets all the types of excluded parameters. For each type the following are shown: the ID and the name. ascan.api.view.messagesIds = Gets the IDs of the messages sent during the scan with the given ID. A message can be obtained with 'message' core view. -ascan.api.view.messagesIds.param.scanId = +ascan.api.view.messagesIds.param.scanId = +ascan.api.view.messagesIdsWithError = Gets the IDs of the messages sent during the scan with the given ID and which threw an error (e.g. IOException). A message can be obtained with 'message' core view. +ascan.api.view.messagesIdsWithError.param.scanId = ascan.api.view.optionAddQueryParam = Tells whether or not the active scanner should add a query parameter to GET request that don't have parameters to start with. ascan.api.view.optionAllowAttackOnStart = ascan.api.view.optionAttackPolicy = @@ -590,13 +592,15 @@ ascan.toolbar.button.new = New Scan ascan.toolbar.button.stop = Stop Active Scan ascan.toolbar.button.unpause = Resume Active Scan ascan.toolbar.confirm.clear = Are you sure you want to clear all completed scans? - ascan.toolbar.newalerts.label = New Alerts: +ascan.toolbar.newalerts.label = New Alerts: ascan.toolbar.requests.label = Num Requests: ascan.toolbar.progress.label = Progress: ascan.toolbar.progress.select = --Select Scan-- ascan.url.popup = Active Scan single URL ascan.panel.tab.scannedMessages = Sent Messages -ascan.panel.tab.filteredMessages = Filtered Messages +ascan.panel.tab.scannedMessages.column.processed = Processed +ascan.panel.tab.scannedMessages.column.processed.successfully = Successfully +ascan.panel.tab.filteredMessages = Filtered Messages ascan.filter.table.header.url = URL ascan.filter.table.header.reason = Reason diff --git a/zap/zap.gradle.kts b/zap/zap.gradle.kts index be95ba65ade..4a6afcf7a08 100644 --- a/zap/zap.gradle.kts +++ b/zap/zap.gradle.kts @@ -160,7 +160,7 @@ val japicmp by tasks.registering(JapicmpTask::class) { classExcludes = listOf() - methodExcludes = listOf() + methodExcludes = listOf("org.parosproxy.paros.core.scanner.ScannerListener#notifyNewTaskResult(org.zaproxy.zap.extension.ascan.ScannerTaskResult)") richReport { destinationDir = file("$buildDir/reports/japicmp/")