diff --git a/zap/src/main/java/org/parosproxy/paros/core/scanner/Category.java b/zap/src/main/java/org/parosproxy/paros/core/scanner/Category.java index fee9064daae..0f96fad3d79 100644 --- a/zap/src/main/java/org/parosproxy/paros/core/scanner/Category.java +++ b/zap/src/main/java/org/parosproxy/paros/core/scanner/Category.java @@ -45,6 +45,8 @@ public class Category { Constant.messages.getString("scanner.category.inject") }; + private static final String[] keys = {"info", "browser", "server", "misc", "inject"}; + public static String getName(int category) { String result = Constant.messages.getString("scanner.category.undef"); if (category < names.length) { @@ -53,6 +55,14 @@ public static String getName(int category) { return result; } + /** Returns the stable, non-i18n key for the given category, e.g. {@code "server"}. */ + public static String getKey(int category) { + if (category >= 0 && category < keys.length) { + return keys[category]; + } + return "undefined"; + } + public static int getCategory(String name) { for (int i = 0; i < names.length; i++) { if (names[i].equalsIgnoreCase(name)) { diff --git a/zap/src/main/java/org/zaproxy/zap/extension/ascan/ExtensionActiveScan.java b/zap/src/main/java/org/zaproxy/zap/extension/ascan/ExtensionActiveScan.java index 87b07c1110d..40d4a04a7da 100644 --- a/zap/src/main/java/org/zaproxy/zap/extension/ascan/ExtensionActiveScan.java +++ b/zap/src/main/java/org/zaproxy/zap/extension/ascan/ExtensionActiveScan.java @@ -109,6 +109,9 @@ public class ExtensionActiveScan extends ExtensionAdaptor private ActiveScanAPI activeScanApi; + private PluggableScanPolicyManager pluggableScanPolicyManager; + private boolean postInitCalled; + public ExtensionActiveScan() { super(NAME); this.setOrder(28); @@ -124,6 +127,10 @@ public String getUIName() { @Override public void postInit() { policyManager.init(); + postInitCalled = true; + if (pluggableScanPolicyManager != null) { + pluggableScanPolicyManager.register(policyManager); + } if (Control.getSingleton().getMode().equals(Mode.attack)) { if (hasView() && !this.getScannerParam().isAllowAttackOnStart()) { @@ -136,6 +143,36 @@ public void postInit() { } } + /** + * Registers a {@link PluggableScanPolicyManager}. If active scan rules are already available, + * {@link PluggableScanPolicyManager#register(PolicyManager)} is called immediately. This is for + * internal ZAP use and is not part of the public API. + * + * @param manager the manager to register; replaces any previously registered manager + * @since 2.18.0 + */ + public void registerPluggableScanPolicyManager(PluggableScanPolicyManager manager) { + this.pluggableScanPolicyManager = manager; + if (postInitCalled) { + manager.register(policyManager); + } + } + + /** + * Unregisters the given {@link PluggableScanPolicyManager}, calling {@link + * PluggableScanPolicyManager#unregister()} if it is currently registered. This is for internal + * ZAP use and is not part of the public API. + * + * @param manager the manager to unregister + * @since 2.18.0 + */ + public void unregisterPluggableScanPolicyManager(PluggableScanPolicyManager manager) { + if (manager == this.pluggableScanPolicyManager) { + manager.unregister(); + this.pluggableScanPolicyManager = null; + } + } + @Override public void hook(ExtensionHook extensionHook) { super.hook(extensionHook); diff --git a/zap/src/main/java/org/zaproxy/zap/extension/ascan/PluggableScanPolicyManager.java b/zap/src/main/java/org/zaproxy/zap/extension/ascan/PluggableScanPolicyManager.java new file mode 100644 index 00000000000..e012a74a369 --- /dev/null +++ b/zap/src/main/java/org/zaproxy/zap/extension/ascan/PluggableScanPolicyManager.java @@ -0,0 +1,41 @@ +/* + * Zed Attack Proxy (ZAP) and its related class files. + * + * ZAP is an HTTP/HTTPS proxy for assessing web application security. + * + * Copyright 2026 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; + +/** + * Extension point allowing add-ons to be notified when active scan rules are available. + * + *
Register an implementation via {@link + * ExtensionActiveScan#registerPluggableScanPolicyManager(PluggableScanPolicyManager)}. + * + * @since 2.18.0 + */ +public interface PluggableScanPolicyManager { + + /** + * Called when active scan rules are available for processing. + * + * @param policyManager the active scan policy manager + */ + void register(PolicyManager policyManager); + + /** Called when active scan rules are being torn down. */ + void unregister(); +} 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 70ac054ecdb..c68cb420cbe 100644 --- a/zap/src/main/resources/org/zaproxy/zap/resources/Messages.properties +++ b/zap/src/main/resources/org/zaproxy/zap/resources/Messages.properties @@ -881,8 +881,8 @@ brk.table.header.type = Type brk.toolbar.button.all.set = Set Break on All Requests and Responses brk.toolbar.button.all.unset = Unset break on all requests and responses brk.toolbar.button.bin = Bin Request or Response -brk.toolbar.button.brkOnlyOnScope.set = Set break only in scope -brk.toolbar.button.brkOnlyOnScope.unset = Unset break only in scope +brk.toolbar.button.brkOnlyOnScope.set = Set Break Only in Scope +brk.toolbar.button.brkOnlyOnScope.unset = Unset Break Only in Scope brk.toolbar.button.brkcssfonts.set = Set can break on CSS and Fonts brk.toolbar.button.brkcssfonts.unset = Set ignore breaks on CSS and Fonts brk.toolbar.button.brkjavascript.set = Set can break on JavaScript @@ -891,10 +891,10 @@ brk.toolbar.button.brkmultimedia.set = Set can break on Multimedia brk.toolbar.button.brkmultimedia.unset = Set ignore breaks on Multimedia brk.toolbar.button.brkpoint = Add a custom HTTP breakpoint... brk.toolbar.button.cont = Submit and Continue to Next Breakpoint -brk.toolbar.button.request.set = Set break on all requests -brk.toolbar.button.request.unset = Unset break on all requests -brk.toolbar.button.response.set = Set break on all responses -brk.toolbar.button.response.unset = Unset break on all responses +brk.toolbar.button.request.set = Set Break on All Requests +brk.toolbar.button.request.unset = Unset Break on All Requests +brk.toolbar.button.response.set = Set Break on All Responses +brk.toolbar.button.response.unset = Unset Break on All Responses brk.toolbar.button.step = Submit and Step to Next Request or Response callback.desc = Provides a URL suitable for calling from target sites