From b23e746f2a3990695734d199ac630ddcbd803580 Mon Sep 17 00:00:00 2001 From: Simon Bennetts Date: Tue, 31 Oct 2023 10:36:24 +0000 Subject: [PATCH] Client: Map initial context menu options Signed-off-by: Simon Bennetts --- addOns/client/CHANGELOG.md | 1 + .../addon/client/ClientDetailsPanel.java | 4 + .../org/zaproxy/addon/client/ClientMap.java | 9 +++ .../zaproxy/addon/client/ClientMapPanel.java | 66 +++++++++++++++- .../org/zaproxy/addon/client/ClientNode.java | 5 ++ .../addon/client/ClientNodeDetailsPanel.java | 4 + .../client/ExtensionClientIntegration.java | 29 +++++++ .../addon/client/PopupMenuClientAttack.java | 48 ++++++++++++ .../addon/client/PopupMenuClientCopyUrls.java | 50 ++++++++++++ .../addon/client/PopupMenuClientDelete.java | 44 +++++++++++ .../client/PopupMenuClientOpenInBrowser.java | 75 ++++++++++++++++++ .../client/PopupMenuClientShowInSites.java | 77 ++++++++++++++++++ .../addon/client/PopupMenuItemClient.java | 54 +++++++++++++ .../PopupMenuItemClientOpenInBrowser.java | 78 +++++++++++++++++++ .../resources/help/contents/client.html | 23 ++++++ .../client/resources/Messages.properties | 6 ++ 16 files changed, 571 insertions(+), 2 deletions(-) create mode 100644 addOns/client/src/main/java/org/zaproxy/addon/client/PopupMenuClientAttack.java create mode 100644 addOns/client/src/main/java/org/zaproxy/addon/client/PopupMenuClientCopyUrls.java create mode 100644 addOns/client/src/main/java/org/zaproxy/addon/client/PopupMenuClientDelete.java create mode 100644 addOns/client/src/main/java/org/zaproxy/addon/client/PopupMenuClientOpenInBrowser.java create mode 100644 addOns/client/src/main/java/org/zaproxy/addon/client/PopupMenuClientShowInSites.java create mode 100644 addOns/client/src/main/java/org/zaproxy/addon/client/PopupMenuItemClient.java create mode 100644 addOns/client/src/main/java/org/zaproxy/addon/client/PopupMenuItemClientOpenInBrowser.java diff --git a/addOns/client/CHANGELOG.md b/addOns/client/CHANGELOG.md index 6da186eab2f..7b724c49455 100644 --- a/addOns/client/CHANGELOG.md +++ b/addOns/client/CHANGELOG.md @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## Unreleased ### Added - Note about custom containers in the help. +- Client Map context menu items. ### Changed - Updated the Chrome extension to v0.0.7. diff --git a/addOns/client/src/main/java/org/zaproxy/addon/client/ClientDetailsPanel.java b/addOns/client/src/main/java/org/zaproxy/addon/client/ClientDetailsPanel.java index 43e6b3e9b80..567cc20a754 100644 --- a/addOns/client/src/main/java/org/zaproxy/addon/client/ClientDetailsPanel.java +++ b/addOns/client/src/main/java/org/zaproxy/addon/client/ClientDetailsPanel.java @@ -71,6 +71,10 @@ public void setClientNode(ClientNode node) { this.setTabFocus(); } + public String getCurrentUrl() { + return this.nodeDetailsPanel.getCurrentUrl(); + } + public void clear() { this.nodeDetailsPanel.clear(); } diff --git a/addOns/client/src/main/java/org/zaproxy/addon/client/ClientMap.java b/addOns/client/src/main/java/org/zaproxy/addon/client/ClientMap.java index 783ab1d4bc1..8f24dfdfa80 100644 --- a/addOns/client/src/main/java/org/zaproxy/addon/client/ClientMap.java +++ b/addOns/client/src/main/java/org/zaproxy/addon/client/ClientMap.java @@ -20,6 +20,7 @@ package org.zaproxy.addon.client; import java.util.Comparator; +import java.util.List; import java.util.Locale; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeNode; @@ -115,6 +116,14 @@ public synchronized ClientNode getOrAddNode(String url, boolean visited, boolean return child; } + public void deleteNodes(List nodes) { + for (ClientNode node : nodes) { + if (!node.isRoot()) { + removeNodeFromParent(node); + } + } + } + public void clear() { root.removeAllChildren(); this.nodeStructureChanged(root); diff --git a/addOns/client/src/main/java/org/zaproxy/addon/client/ClientMapPanel.java b/addOns/client/src/main/java/org/zaproxy/addon/client/ClientMapPanel.java index 58448258502..ad432b48ee8 100644 --- a/addOns/client/src/main/java/org/zaproxy/addon/client/ClientMapPanel.java +++ b/addOns/client/src/main/java/org/zaproxy/addon/client/ClientMapPanel.java @@ -19,21 +19,31 @@ */ package org.zaproxy.addon.client; +import java.awt.Component; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.swing.ImageIcon; +import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTree; +import javax.swing.tree.TreePath; import org.parosproxy.paros.Constant; import org.parosproxy.paros.extension.AbstractPanel; +import org.parosproxy.paros.view.View; import org.zaproxy.zap.view.LayoutHelper; @SuppressWarnings("serial") public class ClientMapPanel extends AbstractPanel { + public static final String CLIENT_TREE_NAME = "treeClient"; + private static final long serialVersionUID = 1L; private ExtensionClientIntegration extension; + private JTree clientTree; private ClientMap clientMap; private JScrollPane scrollPane; @@ -59,11 +69,12 @@ public ClientMapPanel(ExtensionClientIntegration extension, ClientMap clientMap) } public void setClientMap(ClientMap clientMap) { - JTree clientTree = new JTree(clientMap); + clientTree = new JTree(clientMap); clientTree.setShowsRootHandles(true); - clientTree.setName("treeClient"); + clientTree.setName(CLIENT_TREE_NAME); clientTree.setToggleClickCount(1); clientTree.setCellRenderer(new ClientMapTreeCellRenderer()); + clientTree.setComponentPopupMenu(new ClientCustomPopupMenu()); clientTree.addTreeSelectionListener( e -> { @@ -81,4 +92,55 @@ public void clear() { this.clientMap.clear(); } } + + public List getSelectedNodes() { + return Stream.ofNullable(clientTree.getSelectionPaths()) + .flatMap(Stream::of) + .map(TreePath::getLastPathComponent) + .map(ClientNode.class::cast) + .collect(Collectors.toList()); + } + + public void deleteNodes(List nodes) { + for (ClientNode node : nodes) { + if (!node.isRoot()) { + clientMap.removeNodeFromParent(node); + } + } + } + + public ClientNode getSelectedNode() { + return (ClientNode) clientTree.getSelectionPath().getLastPathComponent(); + } + + public ExtensionClientIntegration getExtension() { + return extension; + } + + protected class ClientCustomPopupMenu extends JPopupMenu { + private static final long serialVersionUID = 1L; + + @Override + public void show(Component invoker, int x, int y) { + TreePath tp = clientTree.getPathForLocation(x, y); + if (tp != null) { + boolean select = true; + // Only select a new item if the current item is not + // already selected - this is to allow multiple items + // to be selected + if (clientTree.getSelectionPaths() != null) { + for (TreePath t : clientTree.getSelectionPaths()) { + if (t.equals(tp)) { + select = false; + break; + } + } + } + if (select) { + clientTree.getSelectionModel().setSelectionPath(tp); + } + } + View.getSingleton().getPopupMenu().show(invoker, x, y); + } + } } diff --git a/addOns/client/src/main/java/org/zaproxy/addon/client/ClientNode.java b/addOns/client/src/main/java/org/zaproxy/addon/client/ClientNode.java index 93ae4c5e8ae..8d570a9d92e 100644 --- a/addOns/client/src/main/java/org/zaproxy/addon/client/ClientNode.java +++ b/addOns/client/src/main/java/org/zaproxy/addon/client/ClientNode.java @@ -57,4 +57,9 @@ public String getSite() { } return parent.getSite(); } + + @Override + public String toString() { + return getUserObject().getUrl(); + } } diff --git a/addOns/client/src/main/java/org/zaproxy/addon/client/ClientNodeDetailsPanel.java b/addOns/client/src/main/java/org/zaproxy/addon/client/ClientNodeDetailsPanel.java index 108245d6322..76861520f7e 100644 --- a/addOns/client/src/main/java/org/zaproxy/addon/client/ClientNodeDetailsPanel.java +++ b/addOns/client/src/main/java/org/zaproxy/addon/client/ClientNodeDetailsPanel.java @@ -82,6 +82,10 @@ public void setClientNode(ClientNode node) { .setComponents(new ArrayList<>(node.getUserObject().getComponents())); } + public String getCurrentUrl() { + return this.urlLabel.getText(); + } + public void clear() { this.urlLabel.setText(""); this.getComponentTableModel().setComponents(new ArrayList<>()); diff --git a/addOns/client/src/main/java/org/zaproxy/addon/client/ExtensionClientIntegration.java b/addOns/client/src/main/java/org/zaproxy/addon/client/ExtensionClientIntegration.java index 4a09c444c77..2f93dbdafbb 100644 --- a/addOns/client/src/main/java/org/zaproxy/addon/client/ExtensionClientIntegration.java +++ b/addOns/client/src/main/java/org/zaproxy/addon/client/ExtensionClientIntegration.java @@ -28,6 +28,7 @@ import java.nio.file.StandardOpenOption; import java.util.List; import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.parosproxy.paros.Constant; @@ -39,6 +40,7 @@ import org.parosproxy.paros.extension.SessionChangedListener; import org.parosproxy.paros.extension.history.ExtensionHistory; import org.parosproxy.paros.model.Session; +import org.parosproxy.paros.view.View; import org.zaproxy.addon.client.impl.ClientZestRecorder; import org.zaproxy.addon.network.ExtensionNetwork; import org.zaproxy.zap.ZAP; @@ -106,6 +108,21 @@ public void hook(ExtensionHook extensionHook) { extensionHook.getHookView().addSelectPanel(getClientMapPanel()); extensionHook.getHookView().addWorkPanel(getClientDetailsPanel()); extensionHook.getHookView().addStatusPanel(getClientHistoryPanel()); + extensionHook + .getHookMenu() + .addPopupMenuItem(new PopupMenuClientAttack(this.getClientMapPanel())); + extensionHook + .getHookMenu() + .addPopupMenuItem(new PopupMenuClientCopyUrls(this.getClientMapPanel())); + extensionHook + .getHookMenu() + .addPopupMenuItem(new PopupMenuClientDelete(this.getClientMapPanel())); + extensionHook + .getHookMenu() + .addPopupMenuItem(new PopupMenuClientOpenInBrowser(clientMapPanel)); + extensionHook + .getHookMenu() + .addPopupMenuItem(new PopupMenuClientShowInSites(this.getClientMapPanel())); } } @@ -255,6 +272,18 @@ public void clientNodeChanged(ClientNode node) { this.clientTree.nodeChanged(node); } + public void deleteNodes(List nodes) { + this.clientTree.deleteNodes(nodes); + if (View.isInitialised()) { + String displayedUrl = this.getClientDetailsPanel().getCurrentUrl(); + if (StringUtils.isNotBlank(displayedUrl) + && nodes.stream() + .anyMatch(n -> displayedUrl.equals(n.getUserObject().getUrl()))) { + this.getClientDetailsPanel().clear(); + } + } + } + private ClientMapPanel getClientMapPanel() { if (clientMapPanel == null) { clientMapPanel = new ClientMapPanel(this, clientTree); diff --git a/addOns/client/src/main/java/org/zaproxy/addon/client/PopupMenuClientAttack.java b/addOns/client/src/main/java/org/zaproxy/addon/client/PopupMenuClientAttack.java new file mode 100644 index 00000000000..60878486049 --- /dev/null +++ b/addOns/client/src/main/java/org/zaproxy/addon/client/PopupMenuClientAttack.java @@ -0,0 +1,48 @@ +/* + * Zed Attack Proxy (ZAP) and its related class files. + * + * ZAP is an HTTP/HTTPS proxy for assessing web application security. + * + * Copyright 2023 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.addon.client; + +import java.awt.Component; +import java.awt.event.ActionEvent; +import org.parosproxy.paros.Constant; + +public class PopupMenuClientAttack extends PopupMenuItemClient { + + private static final long serialVersionUID = 1L; + + public PopupMenuClientAttack(ClientMapPanel clientMapPanel) { + super(Constant.messages.getString("client.tree.popup.attack"), clientMapPanel); + } + + @Override + public boolean isEnableForComponent(Component invoker) { + boolean enabled = super.isEnableForComponent(invoker); + if (enabled) { + // For now its a placeholder / tease ;) + this.setEnabled(false); + } + return enabled; + } + + @Override + public void performAction(ActionEvent e) { + // Do nothing for now + } +} diff --git a/addOns/client/src/main/java/org/zaproxy/addon/client/PopupMenuClientCopyUrls.java b/addOns/client/src/main/java/org/zaproxy/addon/client/PopupMenuClientCopyUrls.java new file mode 100644 index 00000000000..4cb0b4cd9d5 --- /dev/null +++ b/addOns/client/src/main/java/org/zaproxy/addon/client/PopupMenuClientCopyUrls.java @@ -0,0 +1,50 @@ +/* + * Zed Attack Proxy (ZAP) and its related class files. + * + * ZAP is an HTTP/HTTPS proxy for assessing web application security. + * + * Copyright 2023 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.addon.client; + +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.StringSelection; +import java.awt.event.ActionEvent; +import org.parosproxy.paros.Constant; + +public class PopupMenuClientCopyUrls extends PopupMenuItemClient { + + private static final long serialVersionUID = 1L; + + public PopupMenuClientCopyUrls(ClientMapPanel clientMapPanel) { + super(Constant.messages.getString("client.tree.popup.copyurls"), clientMapPanel); + } + + @Override + public void performAction(ActionEvent e) { + StringBuilder sb = new StringBuilder(); + for (ClientNode node : getClientMapPanel().getSelectedNodes()) { + if (!node.isRoot() + && node.getUserObject() != null + && !node.getUserObject().isStorage()) { + sb.append(node.getUserObject().getUrl()); + sb.append('\n'); + } + } + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + clipboard.setContents(new StringSelection(sb.toString()), null); + } +} diff --git a/addOns/client/src/main/java/org/zaproxy/addon/client/PopupMenuClientDelete.java b/addOns/client/src/main/java/org/zaproxy/addon/client/PopupMenuClientDelete.java new file mode 100644 index 00000000000..0d7f23be9b0 --- /dev/null +++ b/addOns/client/src/main/java/org/zaproxy/addon/client/PopupMenuClientDelete.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 2023 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.addon.client; + +import java.awt.event.ActionEvent; +import javax.swing.JOptionPane; +import org.parosproxy.paros.Constant; +import org.parosproxy.paros.view.View; + +public class PopupMenuClientDelete extends PopupMenuItemClient { + + private static final long serialVersionUID = 1L; + + public PopupMenuClientDelete(ClientMapPanel clientMapPanel) { + super(Constant.messages.getString("client.tree.popup.delete"), clientMapPanel); + } + + @Override + public void performAction(ActionEvent e) { + if (View.getSingleton() + .showConfirmDialog( + Constant.messages.getString("client.tree.popup.delete.confirm")) + == JOptionPane.OK_OPTION) { + getClientMapPanel().getExtension().deleteNodes(getClientMapPanel().getSelectedNodes()); + } + } +} diff --git a/addOns/client/src/main/java/org/zaproxy/addon/client/PopupMenuClientOpenInBrowser.java b/addOns/client/src/main/java/org/zaproxy/addon/client/PopupMenuClientOpenInBrowser.java new file mode 100644 index 00000000000..001220f86a5 --- /dev/null +++ b/addOns/client/src/main/java/org/zaproxy/addon/client/PopupMenuClientOpenInBrowser.java @@ -0,0 +1,75 @@ +/* + * Zed Attack Proxy (ZAP) and its related class files. + * + * ZAP is an HTTP/HTTPS proxy for assessing web application security. + * + * Copyright 2023 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.addon.client; + +import java.awt.Component; +import java.util.List; +import javax.swing.JTree; +import org.parosproxy.paros.Constant; +import org.parosproxy.paros.control.Control; +import org.zaproxy.zap.extension.ExtensionPopupMenu; +import org.zaproxy.zap.extension.selenium.Browser; +import org.zaproxy.zap.extension.selenium.ExtensionSelenium; +import org.zaproxy.zap.extension.selenium.ProvidedBrowser; +import org.zaproxy.zap.extension.selenium.ProvidedBrowserUI; + +@SuppressWarnings("serial") +public class PopupMenuClientOpenInBrowser extends ExtensionPopupMenu { + + private static final long serialVersionUID = 1L; + private ClientMapPanel clientMapPanel; + private ExtensionSelenium extSelenium; + + public PopupMenuClientOpenInBrowser(ClientMapPanel clientMapPanel) { + super(Constant.messages.getString("client.tree.popup.browser")); + extSelenium = + Control.getSingleton().getExtensionLoader().getExtension(ExtensionSelenium.class); + + this.clientMapPanel = clientMapPanel; + } + + @Override + public boolean isEnableForComponent(Component invoker) { + if (invoker instanceof JTree) { + JTree tree = (JTree) invoker; + if (ClientMapPanel.CLIENT_TREE_NAME.equals(tree.getName())) { + removeAll(); + for (ProvidedBrowserUI bui : extSelenium.getProvidedBrowserUIList()) { + ProvidedBrowser pbrowser = bui.getBrowser(); + Browser browser = Browser.getBrowserWithId(bui.getBrowser().getId()); + if (!pbrowser.isHeadless()) { + if (browser != null) { + add( + new PopupMenuItemClientOpenInBrowser( + bui.getName(), + extSelenium, + bui.getBrowser(), + clientMapPanel)); + } + } + } + List nodes = clientMapPanel.getSelectedNodes(); + this.setEnabled(nodes.size() == 1 && !nodes.get(0).isRoot()); + return true; + } + } + return false; + } +} diff --git a/addOns/client/src/main/java/org/zaproxy/addon/client/PopupMenuClientShowInSites.java b/addOns/client/src/main/java/org/zaproxy/addon/client/PopupMenuClientShowInSites.java new file mode 100644 index 00000000000..1f99a90cb7f --- /dev/null +++ b/addOns/client/src/main/java/org/zaproxy/addon/client/PopupMenuClientShowInSites.java @@ -0,0 +1,77 @@ +/* + * Zed Attack Proxy (ZAP) and its related class files. + * + * ZAP is an HTTP/HTTPS proxy for assessing web application security. + * + * Copyright 2023 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.addon.client; + +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.util.List; +import org.apache.commons.httpclient.URI; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.parosproxy.paros.Constant; +import org.parosproxy.paros.model.Model; +import org.parosproxy.paros.model.SiteNode; +import org.parosproxy.paros.view.View; + +public class PopupMenuClientShowInSites extends PopupMenuItemClient { + + private static final long serialVersionUID = 1L; + private static final Logger LOGGER = LogManager.getLogger(PopupMenuClientShowInSites.class); + + public PopupMenuClientShowInSites(ClientMapPanel clientMapPanel) { + super(Constant.messages.getString("client.tree.popup.sites"), clientMapPanel); + } + + @Override + public void performAction(ActionEvent e) { + ClientNode node = getClientMapPanel().getSelectedNode(); + + try { + SiteNode siteNode = + Model.getSingleton() + .getSession() + .getSiteTree() + .findNode(new URI(node.getUserObject().getUrl(), true)); + if (siteNode != null) { + View.getSingleton().getSiteTreePanel().showInSites(siteNode); + View.getSingleton() + .getWorkbench() + .getTabbedSelect() + .setSelectedComponent(View.getSingleton().getSiteTreePanel()); + } + } catch (Exception e1) { + LOGGER.error(e1.getMessage(), e1); + } + } + + @Override + public boolean isEnableForComponent(Component invoker) { + boolean enabled = super.isEnableForComponent(invoker); + if (enabled) { + // Disable for multiple nodes, root, and any nodes that have not been visited + List nodes = getClientMapPanel().getSelectedNodes(); + this.setEnabled( + nodes.size() == 1 + && !nodes.get(0).isRoot() + && nodes.get(0).getUserObject().isVisited()); + } + return enabled; + } +} diff --git a/addOns/client/src/main/java/org/zaproxy/addon/client/PopupMenuItemClient.java b/addOns/client/src/main/java/org/zaproxy/addon/client/PopupMenuItemClient.java new file mode 100644 index 00000000000..f72d00dd5f8 --- /dev/null +++ b/addOns/client/src/main/java/org/zaproxy/addon/client/PopupMenuItemClient.java @@ -0,0 +1,54 @@ +/* + * Zed Attack Proxy (ZAP) and its related class files. + * + * ZAP is an HTTP/HTTPS proxy for assessing web application security. + * + * Copyright 2023 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.addon.client; + +import java.awt.Component; +import java.awt.event.ActionEvent; +import javax.swing.JTree; +import org.parosproxy.paros.extension.ExtensionPopupMenuItem; + +public abstract class PopupMenuItemClient extends ExtensionPopupMenuItem { + + private static final long serialVersionUID = 1L; + private ClientMapPanel clientMapPanel; + + public PopupMenuItemClient(String text, ClientMapPanel clientMapPanel) { + super(text); + this.clientMapPanel = clientMapPanel; + this.addActionListener(l -> performAction(l)); + } + + @Override + public boolean isEnableForComponent(Component invoker) { + if (invoker instanceof JTree) { + JTree tree = (JTree) invoker; + if (ClientMapPanel.CLIENT_TREE_NAME.equals(tree.getName())) { + return true; + } + } + return false; + } + + public ClientMapPanel getClientMapPanel() { + return clientMapPanel; + } + + abstract void performAction(ActionEvent e); +} diff --git a/addOns/client/src/main/java/org/zaproxy/addon/client/PopupMenuItemClientOpenInBrowser.java b/addOns/client/src/main/java/org/zaproxy/addon/client/PopupMenuItemClientOpenInBrowser.java new file mode 100644 index 00000000000..50d8855bd61 --- /dev/null +++ b/addOns/client/src/main/java/org/zaproxy/addon/client/PopupMenuItemClientOpenInBrowser.java @@ -0,0 +1,78 @@ +/* + * Zed Attack Proxy (ZAP) and its related class files. + * + * ZAP is an HTTP/HTTPS proxy for assessing web application security. + * + * Copyright 2023 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.addon.client; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.parosproxy.paros.extension.ExtensionPopupMenuItem; +import org.parosproxy.paros.view.View; +import org.zaproxy.zap.extension.selenium.ExtensionSelenium; +import org.zaproxy.zap.extension.selenium.ProvidedBrowser; + +@SuppressWarnings("serial") +public class PopupMenuItemClientOpenInBrowser extends ExtensionPopupMenuItem { + + private static final long serialVersionUID = 1L; + + private static final Logger LOGGER = + LogManager.getLogger(PopupMenuItemClientOpenInBrowser.class); + private ProvidedBrowser browser; + + public PopupMenuItemClientOpenInBrowser( + String label, + ExtensionSelenium ext, + ProvidedBrowser browser, + ClientMapPanel clientMapPanel) { + super(label); + this.browser = browser; + + this.addActionListener( + l -> { + new Thread( + () -> { + try { + ext.getProxiedBrowser( + browser.getId(), + clientMapPanel + .getSelectedNode() + .getUserObject() + .getUrl()); + } catch (Exception e) { + View.getSingleton().showWarningDialog(e.getMessage()); + LOGGER.error(e.getMessage(), e); + } + }) + .start(); + }); + } + + @Override + public boolean isSubMenu() { + return true; + } + + @Override + public boolean isEnabled() { + if (browser == null || !browser.isConfigured()) { + return false; + } + return super.isEnabled(); + } +} diff --git a/addOns/client/src/main/javahelp/org/zaproxy/addon/client/resources/help/contents/client.html b/addOns/client/src/main/javahelp/org/zaproxy/addon/client/resources/help/contents/client.html index bb16aa9201e..40da3b40dd2 100644 --- a/addOns/client/src/main/javahelp/org/zaproxy/addon/client/resources/help/contents/client.html +++ b/addOns/client/src/main/javahelp/org/zaproxy/addon/client/resources/help/contents/client.html @@ -37,6 +37,29 @@

Client Map

Any leaf nodes in the Map with a small red 'minus' sign represent URLs which have been found in the DOM but which have not been directly accessed by ZAP.

Selecting a node that has been visited by ZAP will display details about that node in the Client Details tab. +

+The following context menu items are supported: + +

Copy URLs to Clipboard

+ +Copies the URLs of the selected nodes into the clipboard, separated by newlines. + +

Delete

+ +Deletes the selected nodes. + +

Open in Browser

+ +Opens the selected node in the chosen browser. +This menu item is disabled if multiple nodes are selected. +If the URL contains a fragment then this will be passed to the browser. + +

Show in Sites Tree

+ +Opens the selected node in the Sites Tree. +The message in the Sites Tree does not necessarily match the same message which created the Site Node. +This menu item is disabled if multiple nodes are selected or if the URL has not yet been visited. +If the URL contains a fragment then this will be ignored.

Client Details

diff --git a/addOns/client/src/main/resources/org/zaproxy/addon/client/resources/Messages.properties b/addOns/client/src/main/resources/org/zaproxy/addon/client/resources/Messages.properties index 03018ca80ea..f0d97d30baf 100644 --- a/addOns/client/src/main/resources/org/zaproxy/addon/client/resources/Messages.properties +++ b/addOns/client/src/main/resources/org/zaproxy/addon/client/resources/Messages.properties @@ -21,6 +21,12 @@ client.history.table.header.timestamp = Timestamp client.history.table.header.type = Type client.history.title = Client History client.output.requrl = Client add-on requesting: {0} +client.tree.popup.attack = Attack +client.tree.popup.browser = Open in Browser... +client.tree.popup.copyurls = Copy URLs to Clipboard +client.tree.popup.delete = Delete... +client.tree.popup.delete.confirm = Are you sure you want to delete these Client Nodes? +client.tree.popup.sites = Show in Sites Tree client.tree.title = Client Map client.type.Cookies = Cookies client.type.domMutation = DOM Mutation