org.zaproxy.zap.extension.brk.ExtensionBreak Maven / Gradle / Ivy
Show all versions of zap Show documentation
/*
* Zed Attack Proxy (ZAP) and its related class files.
*
* ZAP is an HTTP/HTTPS proxy for assessing web application security.
*
* Copyright 2010 [email protected]
*
* 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.brk;
import java.awt.Component;
import java.awt.Event;
import java.awt.EventQueue;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.JList;
import javax.swing.JTree;
import javax.swing.KeyStroke;
import javax.swing.tree.TreePath;
import org.apache.log4j.Logger;
import org.parosproxy.paros.Constant;
import org.parosproxy.paros.control.Control;
import org.parosproxy.paros.control.Control.Mode;
import org.parosproxy.paros.extension.ExtensionAdaptor;
import org.parosproxy.paros.extension.ExtensionHook;
import org.parosproxy.paros.extension.ExtensionHookView;
import org.parosproxy.paros.extension.OptionsChangedListener;
import org.parosproxy.paros.extension.SessionChangedListener;
import org.parosproxy.paros.model.HistoryReference;
import org.parosproxy.paros.model.OptionsParam;
import org.parosproxy.paros.model.Session;
import org.parosproxy.paros.model.SiteNode;
import org.parosproxy.paros.view.View;
import org.zaproxy.zap.extension.api.API;
import org.zaproxy.zap.extension.brk.impl.http.HttpBreakpointManagementDaemonImpl;
import org.zaproxy.zap.extension.brk.impl.http.HttpBreakpointMessage;
import org.zaproxy.zap.extension.brk.impl.http.HttpBreakpointMessage.Location;
import org.zaproxy.zap.extension.brk.impl.http.HttpBreakpointMessage.Match;
import org.zaproxy.zap.extension.brk.impl.http.HttpBreakpointsUiManagerInterface;
import org.zaproxy.zap.extension.brk.impl.http.ProxyListenerBreak;
import org.zaproxy.zap.extension.help.ExtensionHelp;
import org.zaproxy.zap.extension.httppanel.Message;
import org.zaproxy.zap.view.ZapMenuItem;
public class ExtensionBreak extends ExtensionAdaptor implements SessionChangedListener, OptionsChangedListener {
/**
* @deprecated (2.6.0) Should not be used/relied on, breakpoint dialogues should be modal.
*/
@Deprecated
public enum DialogType {NONE, ADD, EDIT, REMOVE};
public static final String NAME = "ExtensionBreak";
private static final Logger logger = Logger.getLogger(ExtensionBreak.class);
private BreakPanel breakPanel = null;
private ProxyListenerBreak proxyListener = null;
private BreakpointsPanel breakpointsPanel = null;
private PopupMenuEditBreak popupMenuEditBreak = null;
private PopupMenuRemove popupMenuRemove = null;
private BreakpointMessageHandler2 breakpointMessageHandler;
private DialogType currentDialogType = DialogType.NONE;
private Map, BreakpointsUiManagerInterface> mapBreakpointUiManager;
private Map, BreakpointsUiManagerInterface> mapMessageUiManager;
private Mode mode = Control.getSingleton().getMode();
private BreakpointsParam breakpointsParams;
private BreakpointsOptionsPanel breakpointsOptionsPanel;
private BreakpointManagementInterface breakpointManagementInterface;
private HttpBreakpointsUiManagerInterface httpBreakpoints;
private ZapMenuItem menuBreakOnRequests = null;
private ZapMenuItem menuBreakOnResponses = null;
private ZapMenuItem menuStep = null;
private ZapMenuItem menuContinue = null;
private ZapMenuItem menuDrop = null;
private ZapMenuItem menuHttpBreakpoint = null;
private BreakAPI api = new BreakAPI(this);
public ExtensionBreak() {
super(NAME);
this.setOrder(24);
}
public BreakpointManagementInterface getBreakpointManagementInterface() {
return this.breakpointManagementInterface;
}
/**
* @deprecated (2.6.0) Classes outside of this package should not access the UI directly
*/
@Deprecated
public BreakPanel getBreakPanel() {
return breakPanel;
}
@Override
public void hook(ExtensionHook extensionHook) {
super.hook(extensionHook);
extensionHook.addOptionsParamSet(getOptionsParam());
extensionHook.addProxyListener(getProxyListenerBreak());
extensionHook.addSessionListener(this);
extensionHook.addOptionsChangedListener(this);
API.getInstance().registerApiImplementor(api);
if (getView() != null) {
breakPanel = new BreakPanel(this, getOptionsParam());
breakPanel.setName(Constant.messages.getString("tab.break"));
breakpointMessageHandler = new BreakpointMessageHandler2(breakPanel);
breakpointMessageHandler.setEnabledBreakpoints(getBreakpointsModel().getBreakpointsEnabledList());
breakpointManagementInterface = breakPanel;
ExtensionHookView pv = extensionHook.getHookView();
pv.addWorkPanel(breakPanel);
pv.addOptionPanel(getOptionsPanel());
extensionHook.getHookView().addStatusPanel(getBreakpointsPanel());
extensionHook.getHookMenu().addPopupMenuItem(getPopupMenuEdit());
extensionHook.getHookMenu().addPopupMenuItem(getPopupMenuDelete());
mapBreakpointUiManager = new HashMap<>();
mapMessageUiManager = new HashMap<>();
httpBreakpoints = new HttpBreakpointsUiManagerInterface(extensionHook.getHookMenu(), this);
addBreakpointsUiManager(httpBreakpoints);
extensionHook.getHookMenu().addToolsMenuItem(getMenuToggleBreakOnRequests());
extensionHook.getHookMenu().addToolsMenuItem(getMenuToggleBreakOnResponses());
extensionHook.getHookMenu().addToolsMenuItem(getMenuStep());
extensionHook.getHookMenu().addToolsMenuItem(getMenuContinue());
extensionHook.getHookMenu().addToolsMenuItem(getMenuDrop());
extensionHook.getHookMenu().addToolsMenuItem(getMenuAddHttpBreakpoint());
ExtensionHelp.enableHelpKey(breakPanel, "ui.tabs.break");
ExtensionHelp.enableHelpKey(getBreakpointsPanel(), "ui.tabs.breakpoints");
} else {
this.breakpointManagementInterface = new HttpBreakpointManagementDaemonImpl();
breakpointMessageHandler = new BreakpointMessageHandler2(breakpointManagementInterface);
breakpointMessageHandler.setEnabledBreakpoints(new ArrayList());
}
}
private BreakpointsParam getOptionsParam() {
if (breakpointsParams == null) {
breakpointsParams = new BreakpointsParam();
}
return breakpointsParams;
}
private BreakpointsOptionsPanel getOptionsPanel() {
if (breakpointsOptionsPanel == null) {
breakpointsOptionsPanel = new BreakpointsOptionsPanel();
}
return breakpointsOptionsPanel;
}
private BreakpointsPanel getBreakpointsPanel() {
if (breakpointsPanel == null) {
breakpointsPanel = new BreakpointsPanel(this);
}
return breakpointsPanel;
}
public void addBreakpoint(BreakpointMessageInterface breakpoint) {
this.getBreakpointsPanel().addBreakpoint(breakpoint);
// Switch to the panel for some visual feedback
this.getBreakpointsPanel().setTabFocus();
}
public void editBreakpoint(BreakpointMessageInterface oldBreakpoint, BreakpointMessageInterface newBreakpoint) {
this.getBreakpointsPanel().editBreakpoint(oldBreakpoint, newBreakpoint);
}
public void removeBreakpoint(BreakpointMessageInterface breakpoint) {
this.getBreakpointsPanel().removeBreakpoint(breakpoint);
}
public List getBreakpointsList() {
return getBreakpointsModel().getBreakpointsList();
}
public BreakpointMessageInterface getUiSelectedBreakpoint() {
return getBreakpointsPanel().getSelectedBreakpoint();
}
public void addBreakpointsUiManager(BreakpointsUiManagerInterface uiManager) {
mapBreakpointUiManager.put(uiManager.getBreakpointClass(), uiManager);
mapMessageUiManager.put(uiManager.getMessageClass(), uiManager);
}
public void removeBreakpointsUiManager(BreakpointsUiManagerInterface uiManager) {
mapBreakpointUiManager.remove(uiManager.getBreakpointClass());
mapMessageUiManager.remove(uiManager.getMessageClass());
}
public void setBreakAllRequests(boolean brk) {
this.breakpointManagementInterface.setBreakAllRequests(brk);
}
public void setBreakAllResponses(boolean brk) {
this.breakpointManagementInterface.setBreakAllResponses(brk);
}
public void addHttpBreakpoint(String string, String location, String match, boolean inverse, boolean ignoreCase) {
Location loc;
Match mtch;
try {
loc = Location.valueOf(location);
} catch (Exception e) {
throw new InvalidParameterException("location must be one of " + Arrays.toString(Location.values()));
}
try {
mtch = Match.valueOf(match);
} catch (Exception e) {
throw new InvalidParameterException("match must be one of " + Arrays.toString(Match.values()));
}
this.addBreakpoint(new HttpBreakpointMessage(string, loc, mtch, inverse, ignoreCase));
}
public void removeHttpBreakpoint(String string, String location, String match, boolean inverse, boolean ignoreCase) {
Location loc;
Match mtch;
try {
loc = Location.valueOf(location);
} catch (Exception e) {
throw new InvalidParameterException("location must be one of " + Arrays.toString(Location.values()));
}
try {
mtch = Match.valueOf(match);
} catch (Exception e) {
throw new InvalidParameterException("match must be one of " + Arrays.toString(Match.values()));
}
this.removeBreakpoint(new HttpBreakpointMessage(string, loc, mtch, inverse, ignoreCase));
}
public void addUiBreakpoint(Message aMessage) {
BreakpointsUiManagerInterface uiManager = getBreakpointUiManager(aMessage.getClass());
if (uiManager != null) {
uiManager.handleAddBreakpoint(aMessage);
}
}
private BreakpointsUiManagerInterface getBreakpointUiManager(Class> clazz) {
if (!Message.class.isAssignableFrom(clazz)) {
return null;
}
BreakpointsUiManagerInterface uiManager = mapMessageUiManager.get(clazz);
if (uiManager == null) {
uiManager = getBreakpointUiManager(clazz.getSuperclass());
}
return uiManager;
}
public void editUiSelectedBreakpoint() {
BreakpointMessageInterface breakpoint = getBreakpointsPanel().getSelectedBreakpoint();
if (breakpoint != null) {
BreakpointsUiManagerInterface uiManager = mapBreakpointUiManager.get(breakpoint.getClass());
if (uiManager != null) {
uiManager.handleEditBreakpoint(breakpoint);
}
}
}
public void removeUiSelectedBreakpoint() {
BreakpointMessageInterface breakpoint = getBreakpointsPanel().getSelectedBreakpoint();
if (breakpoint != null) {
BreakpointsUiManagerInterface uiManager = mapBreakpointUiManager.get(breakpoint.getClass());
if (uiManager != null) {
uiManager.handleRemoveBreakpoint(breakpoint);
}
}
}
private BreakpointsTableModel getBreakpointsModel() {
return (BreakpointsTableModel)this.getBreakpointsPanel().getBreakpoints().getModel();
}
private ProxyListenerBreak getProxyListenerBreak() {
if (proxyListener == null) {
proxyListener = new ProxyListenerBreak(getModel(), this);
}
return proxyListener;
}
private PopupMenuEditBreak getPopupMenuEdit() {
if (popupMenuEditBreak == null) {
popupMenuEditBreak = new PopupMenuEditBreak();
popupMenuEditBreak.setExtension(this);
}
return popupMenuEditBreak;
}
private PopupMenuRemove getPopupMenuDelete() {
if (popupMenuRemove == null) {
popupMenuRemove = new PopupMenuRemove();
popupMenuRemove.setExtension(this);
}
return popupMenuRemove;
}
private ZapMenuItem getMenuToggleBreakOnRequests() {
if (menuBreakOnRequests == null) {
menuBreakOnRequests = new ZapMenuItem("menu.tools.brk.req",
KeyStroke.getKeyStroke(KeyEvent.VK_B, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false));
menuBreakOnRequests.addActionListener(new java.awt.event.ActionListener() {
@Override
public void actionPerformed(java.awt.event.ActionEvent e) {
if (getOptionsParam().getButtonMode() == BreakpointsParam.BUTTON_MODE_SIMPLE) {
// Single button mode - toggle break on all
breakpointManagementInterface.setBreakAll(! breakpointManagementInterface.isBreakAll());
} else {
// Toggle break on requests
breakpointManagementInterface.setBreakAllRequests(! breakpointManagementInterface.isBreakRequest());
}
}
});
}
return menuBreakOnRequests;
}
private ZapMenuItem getMenuToggleBreakOnResponses() {
if (menuBreakOnResponses == null) {
menuBreakOnResponses = new ZapMenuItem("menu.tools.brk.resp",
KeyStroke.getKeyStroke(KeyEvent.VK_B, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() | Event.ALT_MASK, false));
menuBreakOnResponses.addActionListener(new java.awt.event.ActionListener() {
@Override
public void actionPerformed(java.awt.event.ActionEvent e) {
if (getOptionsParam().getButtonMode() == BreakpointsParam.BUTTON_MODE_SIMPLE) {
// Single button mode - toggle break on all
breakpointManagementInterface.setBreakAll(! breakpointManagementInterface.isBreakAll());
} else {
// Toggle break on Responses
breakpointManagementInterface.setBreakAllResponses(! breakpointManagementInterface.isBreakResponse());
}
}
});
}
return menuBreakOnResponses;
}
private ZapMenuItem getMenuStep() {
if (menuStep == null) {
menuStep = new ZapMenuItem("menu.tools.brk.step",
KeyStroke.getKeyStroke(KeyEvent.VK_S, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false));
menuStep.addActionListener(new java.awt.event.ActionListener() {
@Override
public void actionPerformed(java.awt.event.ActionEvent e) {
if (breakpointManagementInterface.isHoldMessage(null)) {
// Menu currently always enabled, but dont do anything unless a message is being held
breakpointManagementInterface.step();
}
}
});
}
return menuStep;
}
private ZapMenuItem getMenuContinue() {
if (menuContinue == null) {
menuContinue = new ZapMenuItem("menu.tools.brk.cont",
KeyStroke.getKeyStroke(KeyEvent.VK_C, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false));
menuContinue.addActionListener(new java.awt.event.ActionListener() {
@Override
public void actionPerformed(java.awt.event.ActionEvent e) {
if (breakpointManagementInterface.isHoldMessage(null)) {
// Menu currently always enabled, but dont do anything unless a message is being held
breakpointManagementInterface.cont();
}
}
});
}
return menuContinue;
}
private ZapMenuItem getMenuDrop() {
if (menuDrop == null) {
menuDrop = new ZapMenuItem("menu.tools.brk.drop",
KeyStroke.getKeyStroke(KeyEvent.VK_X, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false));
menuDrop.addActionListener(new java.awt.event.ActionListener() {
@Override
public void actionPerformed(java.awt.event.ActionEvent e) {
if (breakpointManagementInterface.isHoldMessage(null)) {
// Menu currently always enabled, but dont do anything unless a message is being held
breakpointManagementInterface.drop();
}
}
});
}
return menuDrop;
}
private ZapMenuItem getMenuAddHttpBreakpoint() {
if (menuHttpBreakpoint == null) {
menuHttpBreakpoint = new ZapMenuItem("menu.tools.brk.custom",
KeyStroke.getKeyStroke(KeyEvent.VK_A, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false));
menuHttpBreakpoint.addActionListener(new java.awt.event.ActionListener() {
@Override
public void actionPerformed(java.awt.event.ActionEvent e) {
// Check to see if anything is selected in the main tabs
String url = "";
Component c = View.getSingleton().getMainFrame().getFocusOwner();
if (c != null) {
if (c instanceof JList) {
// Handles the history list and similar
@SuppressWarnings("rawtypes")
Object sel = ((JList)c).getSelectedValue();
try {
if (sel != null && sel instanceof HistoryReference &&
((HistoryReference)sel).getURI() != null) {
url = ((HistoryReference)sel).getURI().toString();
}
} catch (Exception e1) {
// Ignore
}
} else if (c instanceof JTree) {
// Handles the Sites tree
TreePath path = ((JTree)c).getSelectionPath();
try {
if (path != null && path.getLastPathComponent() instanceof SiteNode) {
url = ((SiteNode)path.getLastPathComponent()).getHistoryReference().getURI().toString();
}
} catch (Exception e1) {
// Ignore
}
}
}
httpBreakpoints.handleAddBreakpoint(url);
}
});
}
return menuHttpBreakpoint;
}
/**
* @deprecated (2.6.0) Use modal breakpoint dialogues instead of relying on this behaviour.
*/
@Deprecated
public boolean canAddBreakpoint() {
return (currentDialogType == DialogType.NONE || currentDialogType == DialogType.ADD);
}
/**
* @deprecated (2.6.0) Use modal breakpoint dialogues instead of relying on this behaviour.
*/
@Deprecated
public boolean canEditBreakpoint() {
return (currentDialogType == DialogType.NONE || currentDialogType == DialogType.EDIT);
}
/**
* @deprecated (2.6.0) Use modal breakpoint dialogues instead of relying on this behaviour.
*/
@Deprecated
public boolean canRemoveBreakpoint() {
return (currentDialogType == DialogType.NONE || currentDialogType == DialogType.REMOVE);
}
/**
* @deprecated (2.6.0) Use modal breakpoint dialogues instead of relying on this behaviour.
*/
@Deprecated
public void dialogShown(DialogType type) {
currentDialogType = type;
}
/**
* @deprecated (2.6.0) Use modal breakpoint dialogues instead of relying on this behaviour.
*/
@Deprecated
public void dialogClosed() {
currentDialogType = DialogType.NONE;
}
@Override
public String getAuthor() {
return Constant.ZAP_TEAM;
}
@Override
public String getDescription() {
return Constant.messages.getString("brk.desc");
}
@Override
public URL getURL() {
try {
return new URL(Constant.ZAP_HOMEPAGE);
} catch (MalformedURLException e) {
return null;
}
}
@Override
public void sessionAboutToChange(final Session session) {
if (EventQueue.isDispatchThread()) {
sessionAboutToChange();
} else {
try {
EventQueue.invokeAndWait(new Runnable() {
@Override
public void run() {
sessionAboutToChange();
}
});
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
}
@Override
public void sessionChanged(Session session) {
if (getView() == null) {
return;
}
breakpointManagementInterface.init();
}
private void sessionAboutToChange() {
if (getView() == null) {
return;
}
breakpointManagementInterface.reset();
}
@Override
public void sessionScopeChanged(Session session) {
}
@Override
public void destroy() {
if (breakPanel != null) {
breakPanel.savePanels();
}
}
public boolean messageReceivedFromClient(Message aMessage) {
if (mode.equals(Mode.safe)) {
return true;
}
return breakpointMessageHandler.handleMessageReceivedFromClient(aMessage, mode.equals(Mode.protect));
}
public boolean messageReceivedFromServer(Message aMessage) {
if (mode.equals(Mode.safe)) {
return true;
}
return breakpointMessageHandler.handleMessageReceivedFromServer(aMessage, mode.equals(Mode.protect));
}
/**
* Exposes list of enabled breakpoints.
*
* @return list of enabled breakpoints
*/
public List getBreakpointsEnabledList() {
if (mode.equals(Mode.safe)) {
return new ArrayList<>();
}
return getBreakpointsModel().getBreakpointsEnabledList();
}
@Override
public void sessionModeChanged(Mode mode) {
this.mode = mode;
if (getView() == null) {
return;
}
this.breakpointManagementInterface.sessionModeChanged(mode);
}
public void setBreakOnId(String id, boolean enable) {
logger.debug("setBreakOnId " + id + " " + enable);
if (enable) {
breakpointMessageHandler.getEnabledKeyBreakpoints().add(id);
} else {
breakpointMessageHandler.getEnabledKeyBreakpoints().remove(id);
}
}
@Override
public void optionsChanged(OptionsParam optionsParam) {
applyViewOptions(optionsParam);
}
/**
* Applies the given (view) options to the break components, by setting the location of the break buttons and the break
* buttons mode.
*
* The call to this method has no effect if there's no view.
*
* @param options the current options
*/
private void applyViewOptions(OptionsParam options) {
if (getView() == null) {
return;
}
breakPanel.setButtonsLocation(options.getViewParam().getBrkPanelViewOption());
breakPanel.setButtonMode(options.getParamSet(BreakpointsParam.class).getButtonMode());
}
@Override
public void optionsLoaded() {
applyViewOptions(getModel().getOptionsParam());
}
public boolean isInScopeOnly() {
return this.getOptionsParam().isInScopeOnly();
}
@Override
/**
* No database tables used, so all supported
*/
public boolean supportsDb(String type) {
return true;
}
}