diff --git a/addOns/scripts/CHANGELOG.md b/addOns/scripts/CHANGELOG.md index 1aae22337d9..591574ece19 100644 --- a/addOns/scripts/CHANGELOG.md +++ b/addOns/scripts/CHANGELOG.md @@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Fields with default or missing values are omitted for the `script` job in saved Automation Framework plans. - Depends on an updated version of the Common Library add-on. - Depend on Passive Scanner add-on (Issue 7959). +- Use the main Output panel for script output. ### Fixed - Correct auto-complete suggestions for parameters of Passive Rules. diff --git a/addOns/scripts/src/main/java/org/zaproxy/zap/extension/scripts/ConsolePanel.java b/addOns/scripts/src/main/java/org/zaproxy/zap/extension/scripts/ConsolePanel.java index 2eed72f38ce..979d61f20b6 100644 --- a/addOns/scripts/src/main/java/org/zaproxy/zap/extension/scripts/ConsolePanel.java +++ b/addOns/scripts/src/main/java/org/zaproxy/zap/extension/scripts/ConsolePanel.java @@ -19,6 +19,8 @@ */ package org.zaproxy.zap.extension.scripts; +import static org.zaproxy.zap.extension.scripts.ExtensionScriptsUI.extractScriptExceptionMessage; + import java.awt.BorderLayout; import java.awt.GridBagLayout; import java.awt.Toolkit; @@ -46,7 +48,6 @@ import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; -import javax.swing.JSplitPane; import javax.swing.JToolBar; import javax.swing.KeyStroke; import javax.swing.border.EmptyBorder; @@ -86,7 +87,6 @@ public class ConsolePanel extends AbstractPanel { private JButton optionsButton; private JLabel scriptTitle = null; private CommandPanel commandPanel = null; - private OutputPanel outputPanel = null; private KeyListener listener = null; private ScriptWrapper script = null; @@ -135,15 +135,8 @@ public ConsolePanel(ExtensionScriptsUI extension) { panelContent = new JPanel(new GridBagLayout()); this.add(panelContent, BorderLayout.CENTER); - JSplitPane splitPane = new JSplitPane(); - splitPane.setDividerSize(3); - splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT); - splitPane.setResizeWeight(0.5D); - splitPane.setTopComponent(getCommandPanel()); - splitPane.setBottomComponent(getOutputPanel()); - panelContent.add(this.getPanelToolbar(), LayoutHelper.getGBC(0, 0, 1, 1.0D, 0.0D)); - panelContent.add(splitPane, LayoutHelper.getGBC(0, 1, 1, 1.0D, 1.0D)); + panelContent.add(getCommandPanel(), LayoutHelper.getGBC(0, 1, 1, 1.0D, 1.0D)); } private boolean isScriptUpdatedOnDisk() { @@ -456,8 +449,6 @@ private void runScript() { getRunButton().setEnabled(false); - getOutputPanel().preScriptInvoke(); - // Update it, in case its been changed script.setContents(getCommandScript()); @@ -546,19 +537,6 @@ public void actionPerformed(ActionEvent e) { return commandPanel; } - protected OutputPanel getOutputPanel() { - if (outputPanel == null) { - outputPanel = new OutputPanel(extension); - resetOutputPanel(); - } - return outputPanel; - } - - protected void resetOutputPanel() { - outputPanel.clear(); - outputPanel.append(Constant.messages.getString("scripts.welcome.results")); - } - public String getCommandScript() { return this.getCommandPanel().getCommandScript(); } @@ -796,7 +774,12 @@ public void run() { try { extension.getExtScript().invokeScript(script); } catch (Exception e) { - getOutputPanel().append(e); + if (extension.getView() != null) { + extension + .getView() + .getOutputPanel() + .append(extractScriptExceptionMessage(e), script.getName()); + } } finally { WeakReference refScriptExecutorThread = runnableScriptsToThreadMap.remove(script); diff --git a/addOns/scripts/src/main/java/org/zaproxy/zap/extension/scripts/ExtensionScriptsUI.java b/addOns/scripts/src/main/java/org/zaproxy/zap/extension/scripts/ExtensionScriptsUI.java index e45349f4157..4c5f26d7734 100644 --- a/addOns/scripts/src/main/java/org/zaproxy/zap/extension/scripts/ExtensionScriptsUI.java +++ b/addOns/scripts/src/main/java/org/zaproxy/zap/extension/scripts/ExtensionScriptsUI.java @@ -27,6 +27,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import javax.script.ScriptException; import javax.swing.ImageIcon; import javax.swing.TransferHandler; import javax.swing.event.TreeSelectionListener; @@ -35,13 +36,10 @@ import org.apache.logging.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.Extension; import org.parosproxy.paros.extension.ExtensionAdaptor; import org.parosproxy.paros.extension.ExtensionHook; import org.parosproxy.paros.extension.ExtensionPopupMenuItem; -import org.parosproxy.paros.extension.SessionChangedListener; -import org.parosproxy.paros.model.Session; import org.parosproxy.paros.network.HttpMessage; import org.parosproxy.paros.view.OptionsDialog; import org.parosproxy.paros.view.View; @@ -98,8 +96,6 @@ public class ExtensionScriptsUI extends ExtensionAdaptor implements ScriptEventL private ScriptsListPanel scriptsPanel = null; private ConsolePanel consolePanel = null; - private OutputPanelWriter stdOutputPanelWriter = null; - private OutputPanelWriter displayedScriptOutputPanelWriter = null; private InvokeScriptWithHttpMessagePopupMenu popupInvokeScriptWithHttpMessageMenu = null; private PopupEnableDisableScript popupEnableDisableScript = null; @@ -116,12 +112,11 @@ public class ExtensionScriptsUI extends ExtensionAdaptor implements ScriptEventL private ScriptConsoleOptions scriptConsoleOptions; private ScriptConsoleOptionsPanel scriptConsoleOptionsPanel; - private ScriptWrapper currentLockedScript = null; - private boolean lockOutputToDisplayedScript = false; - private final ActiveScriptSynchronizer activeScriptSynchronizer; private final PassiveScriptSynchronizer passiveScriptSynchronizer; + private final Map outputSources = new HashMap<>(); + // private ZapMenuItem menuEnableScripts = null; public ExtensionScriptsUI() { @@ -176,7 +171,6 @@ public void hook(ExtensionHook extensionHook) { optionsDialog.addParamPanel(scriptNode, scriptConsoleOptionsPanel, true); extensionHook.getHookView().addSelectPanel(getScriptsPanel()); - extensionHook.addSessionListener(new ViewSessionChangedListener()); extensionHook.getHookView().addWorkPanel(getConsolePanel()); extensionHook.addOptionsChangedListener(getConsolePanel().getCommandPanel()); extensionHook.getHookMenu().addPopupMenuItem(getPopupInvokeScriptWithHttpMessageMenu()); @@ -285,6 +279,7 @@ public void unload() { } OptionsDialog optionsDialog = View.getSingleton().getOptionsDialog(""); optionsDialog.removeParamPanel(scriptConsoleOptionsPanel); + outputSources.values().forEach(getView().getOutputPanel()::unregisterOutputSource); } activeScriptSynchronizer.unload(); @@ -292,7 +287,6 @@ public void unload() { if (extScript != null) { if (hasView()) { - extScript.removeWriter(getStdOutputPanelWriter()); extScript.removeScriptUI(); } extScript.removeListener(this); @@ -321,7 +315,6 @@ public ExtensionScript getExtScript() { .getExtensionLoader() .getExtension(ExtensionScript.NAME); if (View.isInitialised()) { - extScript.addWriter(getStdOutputPanelWriter()); extScript.setScriptUI(this); } } @@ -434,16 +427,6 @@ public void displayScript(ScriptWrapper script, boolean allowFocus) { return; } - if (this.lockOutputToDisplayedScript) { - // switch writers.. - if (this.currentLockedScript != null) { - // Unset the script specific writer - this.currentLockedScript.setWriter(null); - } - this.currentLockedScript = script; - script.setWriter(this.getDisplayedScriptOutputPanelWriter()); - } - if (script.getEngine() == null) { try { // Scripts loaded from the configs my have loaded before all of the engines @@ -465,26 +448,11 @@ public void displayScript(ScriptWrapper script, boolean allowFocus) { this.getScriptsPanel().showInTree(node); } - if (this.getConsolePanel().getOutputPanel().isClearOnRun()) { - this.getConsolePanel().getOutputPanel().clear(); - - if (script.getLastOutput() != null && script.getLastOutput().length() > 0) { - this.getConsolePanel().getOutputPanel().append(script.getLastOutput()); - } - if (script.getLastException() != null) { - this.showError(script.getLastException()); - } else if (script.getLastErrorDetails() != null - && script.getLastErrorDetails().length() > 0) { - this.showError(script.getLastErrorDetails()); - } - } - - if (!script.getEngine().isTextBased() - && this.getConsolePanel().getOutputPanel().isEmpty()) { + if (!script.getEngine().isTextBased()) { // Output message to explain about non test based scripts this.getConsolePanel() - .getOutputPanel() - .append(Constant.messages.getString("scripts.welcome.nontest")); + .getCommandPanel() + .setCommandScript(Constant.messages.getString("scripts.welcome.nontest")); } } } @@ -524,7 +492,7 @@ public void displayTemplate(ScriptWrapper script) { this.getScriptsPanel().showInTree(node); } - this.getConsolePanel().getOutputPanel().clear(); + this.getConsolePanel().getCommandPanel().clear(); } } @@ -549,18 +517,17 @@ private void displayTypeImpl(ScriptType type, boolean template) { // Save any changes to previous script this.saveChanges(); + String displayText = ""; this.getConsolePanel().clearScript(); - OutputPanel outputPanel = getConsolePanel().getOutputPanel(); - outputPanel.clear(); if (template) { - outputPanel.append(Constant.messages.getString("scripts.template.desc")); + displayText += Constant.messages.getString("scripts.template.desc"); } if (Constant.messages.containsKey(type.getI18nKey() + ".desc")) { - outputPanel.append(Constant.messages.getString(type.getI18nKey() + ".desc")); - this.getConsolePanel().setTabFocus(); + displayText += Constant.messages.getString(type.getI18nKey() + ".desc"); } + getConsolePanel().getCommandPanel().setCommandScript(displayText); } void displayTemplateType(ScriptType type) { @@ -586,33 +553,12 @@ public String getDescription() { return Constant.messages.getString("scripts.desc"); } - /* - * The writer that will get output from all scripts run - */ - private OutputPanelWriter getStdOutputPanelWriter() { - if (View.isInitialised() && stdOutputPanelWriter == null) { - stdOutputPanelWriter = new OutputPanelWriter(this.getConsolePanel().getOutputPanel()); - } - return stdOutputPanelWriter; - } - - /* - * The writer which will get output only for the script currently being displayed - */ - private OutputPanelWriter getDisplayedScriptOutputPanelWriter() { - if (View.isInitialised() && displayedScriptOutputPanelWriter == null) { - displayedScriptOutputPanelWriter = - new OutputPanelWriter(this.getConsolePanel().getOutputPanel()); - } - return this.displayedScriptOutputPanelWriter; - } - public void invokeTargetedScript(ScriptWrapper script, HttpMessage msg) { if (View.isInitialised()) { executeInEdt( () -> { this.displayScript(script); - this.getConsolePanel().getOutputPanel().preScriptInvoke(); + this.preInvoke(script); this.getConsolePanel().setTabFocus(); }); } @@ -621,8 +567,11 @@ public void invokeTargetedScript(ScriptWrapper script, HttpMessage msg) { @Override public void preInvoke(ScriptWrapper script) { - if (this.isScriptDisplayed(script)) { - this.getConsolePanel().getOutputPanel().preScriptInvoke(); + if (script != null + && hasView() + && outputSources.get(script) != null + && outputSources.get(script).isClearOnRun()) { + getView().getOutputPanel().clear(script.getName()); } } @@ -639,8 +588,14 @@ public void refreshScript(ScriptWrapper script) { @Override public void scriptAdded(ScriptWrapper script, boolean display) { - if (View.isInitialised() && display) { - executeInEdt(() -> this.displayScript(script)); + if (hasView()) { + if (display) { + executeInEdt(() -> this.displayScript(script)); + } + var outputSource = new ScriptOutputSource(script); + outputSources.put(script, outputSource); + getView().getOutputPanel().registerOutputSource(outputSource); + script.setWriter(new OutputPanelWriter(getView().getOutputPanel(), script.getName())); } switch (script.getType().getName()) { case SCRIPT_EXT_TYPE: @@ -690,8 +645,12 @@ public void scriptRemoved(ScriptWrapper script) { passiveScriptSynchronizer.scriptRemoved(script); break; } - if (View.isInitialised()) { + if (hasView()) { this.getConsolePanel().removeScript(script); + var outputSource = outputSources.remove(script); + if (outputSource != null) { + getView().getOutputPanel().unregisterOutputSource(outputSource); + } } } @@ -726,11 +685,15 @@ public void scriptChanged(ScriptWrapper script) { @Override public void scriptError(ScriptWrapper script) { - if (this.isScriptDisplayed(script)) { + if (hasView()) { if (script.getLastException() != null) { - this.showError(script.getLastException()); + getView() + .getOutputPanel() + .append( + extractScriptExceptionMessage(script.getLastException()), + script.getName()); } else { - this.showError(script.getLastErrorDetails()); + getView().getOutputPanel().append(script.getLastErrorDetails(), script.getName()); } } } @@ -747,26 +710,24 @@ public void scriptSaved(ScriptWrapper script) { } } + @Deprecated(since = "45.8.0", forRemoval = true) public void showError(Exception e) { - if (View.isInitialised()) { - this.getConsolePanel().getOutputPanel().append(e); - } else { - System.out.println("ERROR: " + e); - } + showError(extractScriptExceptionMessage(e)); } + @Deprecated(since = "45.8.0", forRemoval = true) public void showError(String string) { - if (View.isInitialised()) { - this.getConsolePanel().getOutputPanel().appendError(string); + if (hasView()) { + getView().getOutputPanel().append(string, NAME); } else { System.out.println("ERROR: " + string); } } + @Deprecated(since = "45.8.0", forRemoval = true) public void setOutput(String string) { if (View.isInitialised()) { - this.getConsolePanel().getOutputPanel().clear(); - this.getConsolePanel().getOutputPanel().append(string); + getView().getOutputPanel().append(string, NAME); } } @@ -870,35 +831,21 @@ public List> getDependencies() { return EXTENSION_DEPENDENCIES; } + @Deprecated(since = "45.8.0", forRemoval = true) public boolean isLockOutputToDisplayedScript() { - return lockOutputToDisplayedScript; + return true; } - public void setLockOutputToDisplayedScript(boolean lockOutputToDisplayedScript) { - this.lockOutputToDisplayedScript = lockOutputToDisplayedScript; - - this.getStdOutputPanelWriter().setEnabled(!lockOutputToDisplayedScript); - this.getDisplayedScriptOutputPanelWriter().setEnabled(lockOutputToDisplayedScript); - - if (this.currentLockedScript != null) { - this.currentLockedScript.setWriter(null); - } - - ScriptWrapper script = this.getScriptsPanel().getSelectedScript(); - if (script != null) { - if (this.lockOutputToDisplayedScript) { - script.setWriter(this.getDisplayedScriptOutputPanelWriter()); - this.currentLockedScript = script; - } else { - script.setWriter(null); - this.currentLockedScript = null; - } - } - } + @Deprecated(since = "45.8.0", forRemoval = true) + public void setLockOutputToDisplayedScript(boolean lockOutputToDisplayedScript) {} @Override + @Deprecated(since = "45.8.0", forRemoval = true) public Writer getOutputWriter() { - return this.getStdOutputPanelWriter(); + if (hasView()) { + return new OutputPanelWriter(getView().getOutputPanel(), NAME); + } + return null; } @Override @@ -979,28 +926,17 @@ private void uninstallExtenderScript(ScriptWrapper script) { } } - /** A {@code SessionChangedListener} for view/UI related functionalities. */ - private class ViewSessionChangedListener implements SessionChangedListener { - - @Override - public void sessionAboutToChange(Session session) { - getConsolePanel().resetOutputPanel(); + static String extractScriptExceptionMessage(Exception e) { + if (e instanceof ScriptException) { + return e.getMessage(); } - - @Override - public void sessionChanged(Session session) { - // Nothing to do. - } - - @Override - public void sessionModeChanged(Mode mode) { - // Nothing to do. - } - - @Override - public void sessionScopeChanged(Session session) { - // Nothing to do. + Throwable cause; + while ((cause = e.getCause()) != null) { + if (cause instanceof ScriptException) { + return cause.getMessage(); + } } + return e.toString(); } static class BuiltInScript { diff --git a/addOns/scripts/src/main/java/org/zaproxy/zap/extension/scripts/OutputPanel.java b/addOns/scripts/src/main/java/org/zaproxy/zap/extension/scripts/OutputPanel.java deleted file mode 100644 index 60b8103afa2..00000000000 --- a/addOns/scripts/src/main/java/org/zaproxy/zap/extension/scripts/OutputPanel.java +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Zed Attack Proxy (ZAP) and its related class files. - * - * ZAP is an HTTP/HTTPS proxy for assessing web application security. - * - * Copyright 2012 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.scripts; - -import java.awt.BorderLayout; -import java.awt.EventQueue; -import javax.script.ScriptException; -import javax.swing.ImageIcon; -import javax.swing.JButton; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JToolBar; -import javax.swing.text.DefaultCaret; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.parosproxy.paros.Constant; -import org.parosproxy.paros.extension.AbstractPanel; -import org.zaproxy.zap.utils.DisplayUtils; -import org.zaproxy.zap.utils.FontUtils; -import org.zaproxy.zap.utils.ZapTextArea; -import org.zaproxy.zap.view.ZapToggleButton; - -@SuppressWarnings("serial") -public class OutputPanel extends AbstractPanel { - - private static final long serialVersionUID = -947074835463140074L; - private static final Logger LOGGER = LogManager.getLogger(OutputPanel.class); - - private static final ImageIcon CLEAR_ICON = - new ImageIcon( - OutputPanel.class.getResource( - "/org/zaproxy/zap/extension/scripts/resources/icons/broom.png")); - private static final ImageIcon CLEAR_ON_RUN_DISABLED_ICON = - new ImageIcon( - OutputPanel.class.getResource( - "/org/zaproxy/zap/extension/scripts/resources/icons/broom-play-disabled.png")); - private static final ImageIcon CLEAR_ON_RUN_ENABLED_ICON = - new ImageIcon( - OutputPanel.class.getResource( - "/org/zaproxy/zap/extension/scripts/resources/icons/broom-play-enabled.png")); - private static final ImageIcon SCROLL_LOCK_DISABLED_ICON = - new ImageIcon( - OutputPanel.class.getResource( - "/org/zaproxy/zap/extension/scripts/resources/icons/ui-scroll-pane.png")); - private static final ImageIcon SCROLL_LOCK_ENABLED_ICON = - new ImageIcon( - OutputPanel.class.getResource( - "/org/zaproxy/zap/extension/scripts/resources/icons/ui-scroll-lock-pane.png")); - - private ExtensionScriptsUI extension; - private JPanel mainPanel; - private JToolBar mainToolBar; - private JScrollPane jScrollPane = null; - private ZapTextArea txtOutput = null; - private boolean clearOnRun = false; - - /** - * @param extension - */ - public OutputPanel(ExtensionScriptsUI extension) { - super(); - this.extension = extension; - - this.setLayout(new BorderLayout()); - this.setName("ConsoleOutputPanel"); - this.add(getMainPanel(), BorderLayout.CENTER); - } - - private JPanel getMainPanel() { - if (mainPanel == null) { - mainPanel = new JPanel(new BorderLayout()); - mainPanel.add(getToolBar(), BorderLayout.PAGE_START); - mainPanel.add(getJScrollPane(), BorderLayout.CENTER); - } - return mainPanel; - } - - private JToolBar getToolBar() { - if (mainToolBar == null) { - mainToolBar = new JToolBar(); - mainToolBar.setEnabled(true); - mainToolBar.setFloatable(false); - mainToolBar.setRollover(true); - - final JButton clearButton = new JButton(); - clearButton.setToolTipText( - Constant.messages.getString("scripts.output.clear.button.toolTip")); - clearButton.setIcon(DisplayUtils.getScaledIcon(CLEAR_ICON)); - clearButton.addActionListener(e -> getTxtOutput().setText("")); - - final ZapToggleButton clearOnRunButton = new ZapToggleButton(); - clearOnRunButton.setToolTipText( - Constant.messages.getString( - "scripts.output.clearOnRun.button.disabled.toolTip")); - clearOnRunButton.setSelectedToolTipText( - Constant.messages.getString( - "scripts.output.clearOnRun.button.enabled.toolTip")); - clearOnRunButton.setIcon(DisplayUtils.getScaledIcon(CLEAR_ON_RUN_DISABLED_ICON)); - clearOnRunButton.setSelectedIcon(DisplayUtils.getScaledIcon(CLEAR_ON_RUN_ENABLED_ICON)); - clearOnRunButton.addActionListener(e -> clearOnRun = clearOnRunButton.isSelected()); - - final ZapToggleButton scrollLockButton = new ZapToggleButton(); - scrollLockButton.setToolTipText( - Constant.messages.getString( - "scripts.output.scrolllock.button.disabled.toolTip")); - scrollLockButton.setSelectedToolTipText( - Constant.messages.getString( - "scripts.output.scrolllock.button.enabled.toolTip")); - scrollLockButton.setIcon(DisplayUtils.getScaledIcon(SCROLL_LOCK_DISABLED_ICON)); - scrollLockButton.setSelectedIcon(DisplayUtils.getScaledIcon(SCROLL_LOCK_ENABLED_ICON)); - scrollLockButton.addActionListener( - e -> { - if (scrollLockButton.isSelected()) { - DefaultCaret caret = (DefaultCaret) getTxtOutput().getCaret(); - caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE); - } else { - DefaultCaret caret = (DefaultCaret) getTxtOutput().getCaret(); - caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE); - getTxtOutput() - .setCaretPosition(getTxtOutput().getDocument().getLength()); - } - }); - - final ZapToggleButton scriptLockButton = new ZapToggleButton(); - scriptLockButton.setToolTipText( - Constant.messages.getString( - "scripts.output.scriptLock.button.disabled.toolTip")); - scriptLockButton.setSelectedToolTipText( - Constant.messages.getString( - "scripts.output.scriptLock.button.enabled.toolTip")); - scriptLockButton.setIcon(DisplayUtils.getScaledIcon(ExtensionScriptsUI.getIcon())); - scriptLockButton.addActionListener( - e -> extension.setLockOutputToDisplayedScript(scriptLockButton.isSelected())); - - mainToolBar.add(clearButton); - mainToolBar.add(clearOnRunButton); - mainToolBar.add(scrollLockButton); - mainToolBar.add(scriptLockButton); - } - return mainToolBar; - } - - /** - * This method initializes jScrollPane - * - * @return javax.swing.JScrollPane - */ - private JScrollPane getJScrollPane() { - if (jScrollPane == null) { - jScrollPane = new JScrollPane(); - jScrollPane.setViewportView(getTxtOutput()); - jScrollPane.setName("ConsoleScrollPane"); - jScrollPane.setHorizontalScrollBarPolicy( - javax.swing.JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); - jScrollPane.setFont(FontUtils.getFont("Dialog")); - } - return jScrollPane; - } - - /** - * This method initializes txtOutput - * - * @return org.zaproxy.zap.utils.ZapTextArea - */ - private ZapTextArea getTxtOutput() { - if (txtOutput == null) { - txtOutput = new ZapTextArea(); - txtOutput.setEditable(false); - txtOutput.setLineWrap(true); - txtOutput.setFont(FontUtils.getFont("Dialog")); - txtOutput.setName(""); - txtOutput.setComponentPopupMenu(ZapPopupMenu.INSTANCE); - } - return txtOutput; - } - - public void append(final String msg) { - if (EventQueue.isDispatchThread()) { - getTxtOutput().append(msg); - return; - } - try { - EventQueue.invokeLater(() -> getTxtOutput().append(msg)); - } catch (Exception e) { - if (e instanceof InterruptedException) { - // Ignore - stop button likely to have been used - } else { - LOGGER.error(e.getMessage(), e); - } - } - } - - public void appendError(String str) { - this.append(str); - this.append("\n"); - } - - public void append(final ScriptException e) { - if (Constant.isDevBuild()) { - LOGGER.error(e.getMessage(), e); - } - this.appendError(e.getMessage()); - } - - public void append(final Exception e) { - if (Constant.isDevBuild()) { - LOGGER.error(e.getMessage(), e); - } - Throwable cause = e.getCause(); - while (cause != null) { - if (cause instanceof ScriptException) { - // This is the most useful message - this.appendError(cause.getMessage()); - return; - } - cause = cause.getCause(); - } - // This will have to do - this.appendError(e.toString()); - } - - public void preScriptInvoke() { - if (this.clearOnRun) { - clear(); - } - } - - protected boolean isClearOnRun() { - return this.clearOnRun; - } - - public void clear() { - getTxtOutput().setText(""); - } - - public boolean isEmpty() { - return getTxtOutput().getText().length() == 0; - } -} diff --git a/addOns/scripts/src/main/java/org/zaproxy/zap/extension/scripts/OutputPanelWriter.java b/addOns/scripts/src/main/java/org/zaproxy/zap/extension/scripts/OutputPanelWriter.java index 5aecbe6bb18..f8fbf34c4b2 100644 --- a/addOns/scripts/src/main/java/org/zaproxy/zap/extension/scripts/OutputPanelWriter.java +++ b/addOns/scripts/src/main/java/org/zaproxy/zap/extension/scripts/OutputPanelWriter.java @@ -21,35 +21,31 @@ import java.io.IOException; import java.io.Writer; +import org.parosproxy.paros.view.OutputPanel; public class OutputPanelWriter extends Writer { - private OutputPanel outputPanel; - private boolean enabled = true; + private final String sourceName; + private final OutputPanel outputPanel; - public OutputPanelWriter(OutputPanel outputPanel) { + public OutputPanelWriter(OutputPanel outputPanel, String sourceName) { + this.sourceName = sourceName; this.outputPanel = outputPanel; } @Override public void write(int c) throws IOException { - if (enabled) { - outputPanel.append(String.valueOf((char) c)); - } + outputPanel.append(String.valueOf((char) c), sourceName); } @Override public void write(String str, int off, int len) throws IOException { - if (enabled) { - outputPanel.append(str.substring(off, len)); - } + outputPanel.append(str.substring(off, len), sourceName); } @Override public void write(char[] cbuf, int off, int len) throws IOException { - if (enabled) { - outputPanel.append(new String(cbuf, off, len)); - } + outputPanel.append(new String(cbuf, off, len), sourceName); } @Override @@ -61,12 +57,4 @@ public void flush() throws IOException { public void close() throws IOException { // Ignore } - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } } diff --git a/addOns/scripts/src/main/java/org/zaproxy/zap/extension/scripts/ScriptOutputSource.java b/addOns/scripts/src/main/java/org/zaproxy/zap/extension/scripts/ScriptOutputSource.java new file mode 100644 index 00000000000..4f36631d749 --- /dev/null +++ b/addOns/scripts/src/main/java/org/zaproxy/zap/extension/scripts/ScriptOutputSource.java @@ -0,0 +1,91 @@ +/* + * Zed Attack Proxy (ZAP) and its related class files. + * + * ZAP is an HTTP/HTTPS proxy for assessing web application security. + * + * Copyright 2024 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.scripts; + +import java.util.List; +import java.util.Map; +import javax.swing.AbstractButton; +import javax.swing.Icon; +import javax.swing.ImageIcon; +import lombok.EqualsAndHashCode; +import org.parosproxy.paros.Constant; +import org.zaproxy.addon.commonlib.ui.TabbedOutputPanel; +import org.zaproxy.zap.extension.script.ScriptWrapper; +import org.zaproxy.zap.utils.DisplayUtils; +import org.zaproxy.zap.view.OutputSource; +import org.zaproxy.zap.view.ZapToggleButton; + +@EqualsAndHashCode(callSuper = false) +public class ScriptOutputSource extends OutputSource { + + private static final ImageIcon CLEAR_ON_RUN_DISABLED_ICON = + getImageIcon( + "/org/zaproxy/zap/extension/scripts/resources/icons/broom-play-disabled.png"); + private static final ImageIcon CLEAR_ON_RUN_ENABLED_ICON = + getImageIcon( + "/org/zaproxy/zap/extension/scripts/resources/icons/broom-play-enabled.png"); + + private final ScriptWrapper script; + private boolean clearOnRun; + + public ScriptOutputSource(ScriptWrapper script) { + this.script = script; + } + + @Override + public String getName() { + return script.getName(); + } + + @Override + public Map getAttributes() { + return Map.of( + TabbedOutputPanel.ATTRIBUTE_ICON, + getIcon(), + TabbedOutputPanel.ATTRIBUTE_ADDITIONAL_BUTTONS, + getAdditionalButtons()); + } + + boolean isClearOnRun() { + return clearOnRun; + } + + private Icon getIcon() { + return script.getType().getIcon(); + } + + private List getAdditionalButtons() { + var clearOnRunButton = new ZapToggleButton(); + clearOnRunButton.setName("clearOnRunButton"); + clearOnRunButton.setToolTipText( + Constant.messages.getString("scripts.output.clearOnRun.button.disabled.toolTip")); + clearOnRunButton.setSelectedToolTipText( + Constant.messages.getString("scripts.output.clearOnRun.button.enabled.toolTip")); + clearOnRunButton.setIcon(DisplayUtils.getScaledIcon(CLEAR_ON_RUN_DISABLED_ICON)); + clearOnRunButton.setSelectedIcon(DisplayUtils.getScaledIcon(CLEAR_ON_RUN_ENABLED_ICON)); + clearOnRunButton.addActionListener(e -> clearOnRun = clearOnRunButton.isSelected()); + return List.of(clearOnRunButton); + } + + private static ImageIcon getImageIcon(String resourceName) { + return DisplayUtils.getScaledIcon( + new ImageIcon(ScriptOutputSource.class.getResource(resourceName))); + } +} diff --git a/addOns/scripts/src/main/resources/org/zaproxy/zap/extension/scripts/resources/Messages.properties b/addOns/scripts/src/main/resources/org/zaproxy/zap/extension/scripts/resources/Messages.properties index 94c1adf92c7..6b8e808b249 100644 --- a/addOns/scripts/src/main/resources/org/zaproxy/zap/extension/scripts/resources/Messages.properties +++ b/addOns/scripts/src/main/resources/org/zaproxy/zap/extension/scripts/resources/Messages.properties @@ -169,14 +169,6 @@ scripts.options.font.fontSize = Font Size: scripts.options.font.title = Font scripts.options.title = Scripts -scripts.output.clear.button.toolTip = Clear script output panel -scripts.output.clearOnRun.button.disabled.toolTip = Enable clear script output panel on run -scripts.output.clearOnRun.button.enabled.toolTip = Disable clear script output panel on run -scripts.output.scriptLock.button.disabled.toolTip = Enable script lock - only output from the selected script will then be displayed -scripts.output.scriptLock.button.enabled.toolTip = Disable script lock - output from all scripts will then be displayed -scripts.output.scrolllock.button.disabled.toolTip = Enable scroll lock -scripts.output.scrolllock.button.enabled.toolTip = Disable scroll lock - scripts.panel.mnemonic = c scripts.panel.title = Script Console