/* * * Paros and its related class files. * * Paros is an HTTP/HTTPS proxy for assessing web application security. * Copyright (C) 2003-2004 Chinotec Technologies Company * * This program is free software; you can redistribute it and/or * modify it under the terms of the Clarified Artistic License * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * Clarified Artistic License for more details. * * You should have received a copy of the Clarified Artistic License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // ZAP: 2011/08/04 Changed to support new Features // ZAP: 2011/08/04 Changed to support new interface // ZAP: 2012/03/15 Changed so the display options can be modified dynamically. // ZAP: 2012/07/02 Wraps no HttpMessage object, but more generalized Message. // new map of supported message types; removed history list; removed unused // methods. // ZAP: 2012/07/16 Issue 326: Add response time and total length to manual request dialog // ZAP: 2012/07/31 Removed the instance variables followRedirect, // useTrackingSessionState and httpSender. Removed the methods getHttpSender, // getButtonFollowRedirect and getButtonUseTrackingSessionState and changed the // methods windowClosing and setVisible. // ZAP: 2012/08/01 Issue 332: added support for Modes // ZAP: 2012/11/21 Heavily refactored extension to support non-HTTP messages. // ZAP: 2013/05/02 Re-arranged all modifiers into Java coding standard order // ZAP: 2014/01/28 Issue 207: Support keyboard shortcuts // ZAP: 2017/02/20 Issue 2699: Make SSLException handling more user friendly package org.parosproxy.paros.extension.manualrequest; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.HeadlessException; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.net.ssl.SSLException; import javax.swing.JButton; import javax.swing.JPanel; import org.apache.commons.lang.exception.ExceptionUtils; 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.option.OptionsParamView; import org.parosproxy.paros.network.HttpMessage; import org.parosproxy.paros.view.AbstractFrame; import org.parosproxy.paros.view.View; import org.zaproxy.zap.extension.httppanel.HttpPanelRequest; import org.zaproxy.zap.extension.httppanel.Message; import org.zaproxy.zap.extension.tab.Tab; import org.zaproxy.zap.view.ZapMenuItem; /** * Send custom crafted messages via HTTP or other TCP based protocols. */ public abstract class ManualRequestEditorDialog extends AbstractFrame implements Tab { private static final long serialVersionUID = 1L; private static final Logger logger = Logger.getLogger(ManualRequestEditorDialog.class); private boolean isSendEnabled = true; protected String configurationKey; private JPanel panelWindow = null; private JButton btnSend = null; /** * Non-abstract classes should call {@link #initialize()} in their constructor. * * @param isSendEnabled * @param configurationKey * @throws HeadlessException */ public ManualRequestEditorDialog(boolean isSendEnabled, String configurationKey) throws HeadlessException { super(); this.isSendEnabled = isSendEnabled; this.configurationKey = OptionsParamView.BASE_VIEW_KEY + "." + configurationKey + "."; this.setPreferredSize(new Dimension(700, 800)); } protected void initialize() { addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { getMessageSender().cleanup(); saveConfig(); } }); setContentPane(getWindowPanel()); } /** * Returns type of message it handles. * * @return */ public abstract Class<? extends Message> getMessageType(); /** * Message sender for the given {@link #getMessageType()}. * * @return */ protected abstract MessageSender getMessageSender(); /** * Menu item that calls this editor. * * @return */ public abstract ZapMenuItem getMenuItem(); protected JPanel getWindowPanel() { if (panelWindow == null) { panelWindow = new JPanel(); panelWindow.setLayout(new BorderLayout()); panelWindow.add(getManualSendPanel()); } return panelWindow; } protected abstract Component getManualSendPanel(); @Override public void setVisible(boolean show) { if (!show && getMessageSender() != null) { getMessageSender().cleanup(); } super.setVisible(show); } public abstract void setDefaultMessage(); public abstract void setMessage(Message aMessage); public abstract Message getMessage(); public void clear() { getRequestPanel().clearView(); } protected JButton getBtnSend() { if (btnSend == null) { btnSend = new JButton(); btnSend.setText(Constant.messages.getString("manReq.button.send")); btnSend.setEnabled(isSendEnabled); btnSend.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { btnSend.setEnabled(false); // save current message (i.e. set payload/body) getRequestPanel().saveData(); Mode mode = Control.getSingleton().getMode(); if (mode.equals(Mode.safe)) { // Can happen if the user turns on safe mode with the dialog open View.getSingleton().showWarningDialog(Constant.messages.getString("manReq.safe.warning")); btnSend.setEnabled(true); return; } else if (mode.equals(Mode.protect)) { if (!getMessage().isInScope()) { // In protected mode and not in scope, so fail View.getSingleton().showWarningDialog(Constant.messages.getString("manReq.outofscope.warning")); btnSend.setEnabled(true); return; } } btnSendAction(); } }); } return btnSend; } /** * Do not forget to enable the send button again i */ protected abstract void btnSendAction(); protected void send(final Message aMessage) { final Thread t = new Thread(new Runnable() { @Override public void run() { try { getMessageSender().handleSendMessage(aMessage); postSend(); } catch (SSLException sslEx) { StringBuilder strBuilder = new StringBuilder(); strBuilder.append(Constant.messages.getString("network.ssl.error.connect")); strBuilder.append(((HttpMessage) aMessage).getRequestHeader().getURI().toString()).append('\n'); strBuilder.append(Constant.messages.getString("network.ssl.error.exception")).append(sslEx.getMessage()) .append('\n'); strBuilder.append(Constant.messages.getString("network.ssl.error.exception.rootcause")) .append(ExceptionUtils.getRootCauseMessage(sslEx)).append('\n'); strBuilder.append(Constant.messages.getString("network.ssl.error.help", Constant.messages.getString("network.ssl.error.help.url"))); logger.warn(strBuilder.toString()); if (logger.isDebugEnabled()) { logger.debug(sslEx, sslEx); } View.getSingleton().showWarningDialog(strBuilder.toString()); } catch (Exception e) { logger.warn(e.getMessage(), e); View.getSingleton().showWarningDialog(e.getMessage()); } finally { btnSend.setEnabled(true); } } }); t.setPriority(Thread.NORM_PRIORITY); t.start(); } protected void postSend() { EventQueue.invokeLater(new Runnable() { @Override public void run() { // redraw, as message may have changed after sending getRequestPanel().updateContent(); } }); } protected abstract void saveConfig(); protected abstract HttpPanelRequest getRequestPanel(); }