/* * Zed Attack Proxy (ZAP) and its related class files. * * ZAP is an HTTP/HTTPS proxy for assessing web application security. * * 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.httppanel; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Component; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map.Entry; import java.util.regex.Pattern; import javax.swing.BorderFactory; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JToggleButton; import javax.swing.JToolBar; import org.apache.commons.configuration.FileConfiguration; import org.apache.log4j.Logger; import org.parosproxy.paros.Constant; import org.parosproxy.paros.extension.AbstractPanel; import org.zaproxy.zap.extension.httppanel.component.HttpPanelComponentInterface; import org.zaproxy.zap.extension.httppanel.view.HttpPanelDefaultViewSelector; import org.zaproxy.zap.extension.httppanel.view.HttpPanelView; import org.zaproxy.zap.extension.search.SearchMatch; import org.zaproxy.zap.extension.search.SearchableHttpPanelComponent; import org.zaproxy.zap.extension.tab.Tab; public abstract class HttpPanel extends AbstractPanel implements Tab { public enum OptionsLocation {BEGIN, AFTER_COMPONENTS, END}; private static final long serialVersionUID = 5221591643257366570L; private static final Logger logger = Logger.getLogger(HttpPanel.class); private static final String NO_SUITABLE_COMPONENT_FOUND_LABEL = Constant.messages.getString("http.panel.noSuitableComponentFound"); private static final String HTTP_PANEL_KEY = "httppanel."; private static final String COMPONENTS_KEY = "components."; private static final String DEFAULT_COMPONENT_KEY = "defaultcomponent"; private static Comparator<HttpPanelComponentInterface> componentsComparator; private JPanel panelHeader; private JPanel panelContent; private boolean isEditable = false; private boolean isEnableViewSelect = false; protected Message message; private String baseConfigurationKey; private String componentsConfigurationKey; private SwitchComponentItemListener switchComponentItemListener; private Hashtable<String, HttpPanelComponentInterface> components = new Hashtable<>(); private List<HttpPanelComponentInterface> enabledComponents = new ArrayList<>(); private HttpPanelComponentInterface currentComponent; private JPanel noComponentsPanel; private String savedLastSelectedComponentName; private JPanel allOptions; private JPanel componentOptions; private JPanel moreOptionsComponent; private JToolBar toolBarComponents; private JToolBar toolBarMoreOptions; private JPanel endAllOptions; public HttpPanel(boolean isEditable, String configurationKey) { super(); this.isEditable = isEditable; this.message = null; setConfigurationKey(configurationKey); initialize(); initUi(); initSpecial(); } protected abstract void initComponents(); protected abstract void initSpecial(); private void setConfigurationKey(String key) { baseConfigurationKey = key + HTTP_PANEL_KEY; componentsConfigurationKey = baseConfigurationKey + COMPONENTS_KEY; } private void initialize() { this.setLayout(new BorderLayout()); this.add(getPanelHeader(), BorderLayout.NORTH); this.add(getPanelContent(), BorderLayout.CENTER); } private void initUi() { allOptions = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0)); componentOptions = new JPanel(new BorderLayout(0, 0)); moreOptionsComponent = new JPanel(new BorderLayout(0, 0)); toolBarComponents = new JToolBar(); toolBarComponents.setFloatable(false); toolBarComponents.setBorder(BorderFactory.createEmptyBorder()); toolBarComponents.setRollover(true); toolBarMoreOptions = new JToolBar(); toolBarMoreOptions.setFloatable(false); toolBarMoreOptions.setBorder(BorderFactory.createEmptyBorder()); toolBarMoreOptions.setRollover(true); endAllOptions = new JPanel(); JPanel panel1 = new JPanel(new BorderLayout(0, 0)); JPanel panelFlow = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0)); panelFlow.add(allOptions); panelFlow.add(componentOptions); panelFlow.add(toolBarComponents); panelFlow.add(moreOptionsComponent); panelFlow.add(toolBarMoreOptions); panel1.add(panelFlow, BorderLayout.WEST); panelFlow = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0)); panelFlow.add(endAllOptions); panel1.add(panelFlow, BorderLayout.EAST); panelHeader.add(panel1, BorderLayout.NORTH); //getPanelContent().add(new EmptyComponent(), ""); initComponents(); setMessage(null); } private JPanel getPanelContent() { if (panelContent == null) { panelContent = new JPanel(new CardLayout()); } return panelContent; } private JPanel getPanelHeader() { if (panelHeader == null) { panelHeader = new JPanel(new BorderLayout()); } return panelHeader; } public void setMessage(Message msg) { this.message = msg; for(Iterator<Entry<String, HttpPanelComponentInterface>> it = components.entrySet().iterator(); it.hasNext(); ) { HttpPanelComponentInterface component = it.next().getValue(); if (!component.isEnabled(message)) { if (enabledComponents.contains(component)) { disableComponent(component); } } else if (!enabledComponents.contains(component)) { enableComponent(component); } } if (enabledComponents.size() == 0) { currentComponent = null; switchEmptyComponent(); return; } boolean switchView = true; if (currentComponent != null && enabledComponents.contains(components.get(currentComponent.getName()))) { switchView = false; } this.validate(); if (switchView) { switchComponent(enabledComponents.get(0).getName()); } else { updateContent(); } } protected HttpPanelComponentInterface getCurrentComponent() { return currentComponent; } public Message getMessage() { return message; } public void setEditable(boolean editable) { if (isEditable != editable) { isEditable = editable; synchronized (components) { Iterator<HttpPanelComponentInterface> it = components.values().iterator(); while (it.hasNext()) { it.next().setEditable(editable); } } } } public boolean isEditable() { return isEditable; } public void clearView() { setMessage(null); if (currentComponent != null) { currentComponent.clearView(); } } public void setEnableViewSelect(boolean enableViewSelect) { if (isEnableViewSelect != enableViewSelect) { isEnableViewSelect = enableViewSelect; synchronized (components) { Iterator<HttpPanelComponentInterface> it = components.values().iterator(); while (it.hasNext()) { HttpPanelComponentInterface component = it.next(); component.setEnableViewSelect(enableViewSelect); component.getButton().setEnabled(enableViewSelect); } } } } public boolean isEnableViewSelect() { return isEnableViewSelect; } public void clearView(boolean enableViewSelect) { clearView(); setEnableViewSelect(enableViewSelect); } public void setMessage(Message aMessage, boolean enableViewSelect) { setMessage(aMessage); setEnableViewSelect(enableViewSelect); } public void updateContent() { if (currentComponent != null) { currentComponent.setMessage(message); } } public void saveData() { if (message == null || currentComponent == null) { return; } currentComponent.save(); } private void switchComponent(String name) { if (this.currentComponent != null && currentComponent.getName().equals(name)) { currentComponent.setSelected(true); return ; } HttpPanelComponentInterface newComponent = components.get(name); if (newComponent == null) { logger.info("No component found with name: " + name); return; } if (this.currentComponent != null) { currentComponent.setSelected(false); currentComponent.clearView(); if (currentComponent.getOptionsPanel() != null) { componentOptions.remove(0); } if (currentComponent.getMoreOptionsPanel() != null) { moreOptionsComponent.remove(0); } } HttpPanelComponentInterface previousComponent = currentComponent; this.currentComponent = newComponent; updateContent(); JPanel componentOptionsPanel = currentComponent.getOptionsPanel(); if (componentOptionsPanel != null) { componentOptions.add(componentOptionsPanel); } componentOptions.validate(); JPanel componentMoreOptionsPanel = currentComponent.getMoreOptionsPanel(); if (componentMoreOptionsPanel != null) { moreOptionsComponent.add(componentMoreOptionsPanel); } moreOptionsComponent.validate(); ((CardLayout)getPanelContent().getLayout()).show(panelContent, name); currentComponent.setSelected(true); fireComponentChangedEvent(previousComponent, currentComponent); } protected List<HttpPanelComponentInterface> getEnabledComponents() { return enabledComponents; } private void switchEmptyComponent() { if (this.currentComponent != null) { currentComponent.setSelected(false); currentComponent.clearView(); if (currentComponent.getOptionsPanel() != null) { componentOptions.remove(0); } if (currentComponent.getMoreOptionsPanel() != null) { moreOptionsComponent.remove(0); } currentComponent = null; } if (noComponentsPanel == null) { noComponentsPanel = new JPanel(new BorderLayout(5, 5)); noComponentsPanel.add(new JLabel(NO_SUITABLE_COMPONENT_FOUND_LABEL)); getPanelContent().add(new JScrollPane(noComponentsPanel), ""); } componentOptions.removeAll(); componentOptions.validate(); ((CardLayout)getPanelContent().getLayout()).show(panelContent, ""); } public void addOptions(Component comp, OptionsLocation location) { switch (location) { case BEGIN: allOptions.add(comp); break; case AFTER_COMPONENTS: toolBarMoreOptions.add(comp); break; case END: endAllOptions.add(comp); break; default: break; } } public void addOptionsSeparator() { toolBarMoreOptions.addSeparator(); } private void addComponent(HttpPanelComponentInterface component) { synchronized (components) { final String componentName = component.getName(); if (components.containsKey(componentName)) { removeComponent(componentName); } component.setEditable(isEditable); component.setEnableViewSelect(isEnableViewSelect); components.put(componentName, component); panelContent.add(component.getMainPanel(), componentName); final JToggleButton button = component.getButton(); button.setActionCommand(componentName); button.addActionListener(getSwitchComponentItemListener()); button.setEnabled(isEnableViewSelect); if (component.isEnabled(message)) { enableComponent(component); if (currentComponent == null) { switchComponent(componentName); } else if (savedLastSelectedComponentName != null && savedLastSelectedComponentName.equals(componentName)) { switchComponent(componentName); } else if (savedLastSelectedComponentName == null && currentComponent.getPosition() > component.getPosition()) { switchComponent(componentName); } } } } private void enableComponent(HttpPanelComponentInterface component) { enabledComponents.add(component); Collections.sort(enabledComponents, getComponentsComparator()); if (enabledComponents.size() == 1) { toolBarComponents.addSeparator(); toolBarComponents.addSeparator(); } toolBarComponents.add(component.getButton(), enabledComponents.indexOf(component)+1); } private void disableComponent(HttpPanelComponentInterface component) { toolBarComponents.remove(component.getButton()); enabledComponents.remove(component); if (enabledComponents.size() == 0) { toolBarComponents.removeAll(); } } public void addComponent(HttpPanelComponentInterface component, FileConfiguration fileConfiguration) { addComponent(component); component.setParentConfigurationKey(componentsConfigurationKey); component.loadConfig(fileConfiguration); } public void removeComponent(String componentName) { synchronized (components) { HttpPanelComponentInterface component = components.get(componentName); if (component != null) { if (component.isEnabled(message)) { disableComponent(component); } if (enabledComponents.size() > 0) { switchComponent(enabledComponents.get(0).getName()); } else { switchEmptyComponent(); } components.remove(componentName); panelContent.remove(component.getMainPanel()); this.validate(); } } } public void addView(String componentName, HttpPanelView view, Object options, FileConfiguration fileConfiguration) { synchronized (components) { HttpPanelComponentInterface component = components.get(componentName); if (component != null) { component.addView(view, options, fileConfiguration); } } } public void removeView(String componentName, String viewName, Object options) { synchronized (components) { HttpPanelComponentInterface component = components.get(componentName); if (component != null) { component.removeView(viewName, options); } } } public void addDefaultViewSelector(String componentName, HttpPanelDefaultViewSelector defaultViewSelector, Object options) { synchronized (components) { HttpPanelComponentInterface component = components.get(componentName); if (component != null) { component.addDefaultViewSelector(defaultViewSelector, options); } } } public void removeDefaultViewSelector(String componentName, String defaultViewSelectorName, Object options) { synchronized (components) { HttpPanelComponentInterface component = components.get(componentName); if (component != null) { component.removeDefaultViewSelector(defaultViewSelectorName, options); } } } public void loadConfig(FileConfiguration fileConfiguration) { savedLastSelectedComponentName = fileConfiguration.getString(baseConfigurationKey + DEFAULT_COMPONENT_KEY); synchronized (components) { Iterator<HttpPanelComponentInterface> it = components.values().iterator(); while (it.hasNext()) { it.next().loadConfig(fileConfiguration); } } } public void saveConfig(FileConfiguration fileConfiguration) { if (currentComponent != null) { fileConfiguration.setProperty(baseConfigurationKey + DEFAULT_COMPONENT_KEY, currentComponent.getName()); } synchronized (components) { Iterator<HttpPanelComponentInterface> it = components.values().iterator(); while (it.hasNext()) { it.next().saveConfig(fileConfiguration); } } } private static Comparator<HttpPanelComponentInterface> getComponentsComparator() { if (componentsComparator == null) { createComponentsComparator(); } return componentsComparator; } private static synchronized void createComponentsComparator() { if (componentsComparator == null) { componentsComparator = new ComponentsComparator(); } } private static final class ComponentsComparator implements Comparator<HttpPanelComponentInterface>, Serializable { private static final long serialVersionUID = -1380844848294384189L; @Override public int compare(HttpPanelComponentInterface o1, HttpPanelComponentInterface o2) { final int position1 = o1.getPosition(); final int position2 = o2.getPosition(); if (position1 < position2) { return -1; } else if (position1 > position2) { return 1; } return 0; } } private SwitchComponentItemListener getSwitchComponentItemListener() { if (switchComponentItemListener == null) { switchComponentItemListener = new SwitchComponentItemListener(); } return switchComponentItemListener; } private final class SwitchComponentItemListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { if (isEditable()) { saveData(); } switchComponent(e.getActionCommand()); } } public void highlightHeader(SearchMatch sm) { if (currentComponent instanceof SearchableHttpPanelComponent) { ((SearchableHttpPanelComponent)currentComponent).highlightHeader(sm); } else { HttpPanelComponentInterface component = findSearchablePanel(); if (component != null) { switchComponent(component.getName()); ((SearchableHttpPanelComponent)currentComponent).highlightHeader(sm); } } } public void highlightBody(SearchMatch sm) { if (currentComponent instanceof SearchableHttpPanelComponent) { ((SearchableHttpPanelComponent)currentComponent).highlightBody(sm); } else { HttpPanelComponentInterface component = findSearchablePanel(); if (component != null) { switchComponent(component.getName()); ((SearchableHttpPanelComponent)currentComponent).highlightBody(sm); } } } public void headerSearch(Pattern p, List<SearchMatch> matches) { if (currentComponent instanceof SearchableHttpPanelComponent) { ((SearchableHttpPanelComponent)currentComponent).searchHeader(p, matches); } else { HttpPanelComponentInterface component = findSearchablePanel(); if (component != null) { ((SearchableHttpPanelComponent)component).searchHeader(p, matches); } } } public void bodySearch(Pattern p, List<SearchMatch> matches) { if (currentComponent instanceof SearchableHttpPanelComponent) { ((SearchableHttpPanelComponent)currentComponent).searchBody(p, matches); } else { HttpPanelComponentInterface component = findSearchablePanel(); if (component != null) { ((SearchableHttpPanelComponent)component).searchBody(p, matches); } } } private HttpPanelComponentInterface findSearchablePanel() { HttpPanelComponentInterface searchableComponent = null; synchronized (components) { Iterator<HttpPanelComponentInterface> it = components.values().iterator(); while (it.hasNext()) { HttpPanelComponentInterface component = it.next(); if (component instanceof SearchableHttpPanelComponent) { searchableComponent = component; break; } } } return searchableComponent; } public void addMessagePanelEventListener(MessagePanelEventListener listener) { listenerList.add(MessagePanelEventListener.class, listener); } public void removeMessagePanelEventListener(MessagePanelEventListener listener) { listenerList.remove(MessagePanelEventListener.class, listener); } public void fireMessageViewChangedEvent(HttpPanelView previousView, HttpPanelView currentView) { MessageViewSelectedEvent event = null; Object[] listeners = listenerList.getListenerList(); for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == MessagePanelEventListener.class) { if (event == null) { event = new MessageViewSelectedEvent(this, previousView, currentView); } ((MessagePanelEventListener) listeners[i + 1]).viewSelected(event); } } } private void fireComponentChangedEvent( HttpPanelComponentInterface previousComponent, HttpPanelComponentInterface currentComponent) { ComponentChangedEvent event = null; Object[] listeners = listenerList.getListenerList(); for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == MessagePanelEventListener.class) { if (event == null) { event = new ComponentChangedEvent(this, previousComponent, currentComponent); } ((MessagePanelEventListener) listeners[i + 1]).componentChanged(event); } } } }