Skip to content

Commit

Permalink
Merge pull request #3592 from psiinon/scripts/auto-add
Browse files Browse the repository at this point in the history
Scripts: Support auto add/remove script actions
  • Loading branch information
psiinon authored Feb 25, 2022
2 parents 4e2661a + 036675d commit a80fee2
Show file tree
Hide file tree
Showing 13 changed files with 1,096 additions and 93 deletions.
2 changes: 1 addition & 1 deletion addOns/scripts/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## Unreleased
### Added
- Automation ScriptJob - Run a standalone script
- Automation ScriptJob - Add or remove any script and run a standalone script

### Changed
- Update minimum ZAP version to 2.11.1.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
import org.zaproxy.addon.automation.AutomationJob;
import org.zaproxy.addon.automation.AutomationProgress;
import org.zaproxy.addon.automation.jobs.JobUtils;
import org.zaproxy.zap.extension.scripts.automation.actions.AddScriptAction;
import org.zaproxy.zap.extension.scripts.automation.actions.RemoveScriptAction;
import org.zaproxy.zap.extension.scripts.automation.actions.RunScriptAction;
import org.zaproxy.zap.extension.scripts.automation.actions.ScriptAction;
import org.zaproxy.zap.extension.scripts.automation.ui.ScriptJobDialog;
Expand All @@ -40,9 +42,13 @@ public class ScriptJob extends AutomationJob {
public static final String JOB_NAME = "script";
public static final String PARAM_ACTION = "action";
public static final String PARAM_SCRIPT_NAME = "scriptName";
public static final Map<String, Function<ScriptJobParameters, ScriptAction>> ACTIONS =
protected static final Map<String, Function<ScriptJobParameters, ScriptAction>> ACTIONS =
new HashMap<String, Function<ScriptJobParameters, ScriptAction>>() {
private static final long serialVersionUID = 1L;

{
put(AddScriptAction.NAME.toLowerCase(), AddScriptAction::new);
put(RemoveScriptAction.NAME.toLowerCase(), RemoveScriptAction::new);
put(RunScriptAction.NAME.toLowerCase(), RunScriptAction::new);
}
};
Expand All @@ -68,21 +74,25 @@ public void verifyParameters(AutomationProgress progress) {

ScriptAction scriptAction = createScriptAction(progress);
if (scriptAction != null) {
scriptAction.verifyParameters(progress);
scriptAction.verifyParameters(this.getName(), progress);
}
}

@Override
public void applyParameters(AutomationProgress progress) {}
public void applyParameters(AutomationProgress progress) {
// Doesnt need to do anything
}

@Override
public void runJob(AutomationEnvironment env, AutomationProgress progress) {
ScriptAction scriptAction = createScriptAction(progress);
if (scriptAction != null) {
progress.info(
Constant.messages.getString(
"scripts.automation.info.startAction", scriptAction.getName()));
scriptAction.runJob(env, progress);
"scripts.automation.info.startAction",
this.getName(),
scriptAction.getName()));
scriptAction.runJob(this.getName(), env, progress);
}
}

Expand All @@ -102,7 +112,7 @@ public String getSummary() {

@Override
public Order getOrder() {
return Order.REPORT;
return Order.CONFIGS;
}

@Override
Expand Down Expand Up @@ -143,31 +153,34 @@ public String getTemplateDataMax() {
return ExtensionScriptAutomation.getResourceAsString(this.getType() + "-max.yaml");
}

private ScriptAction createScriptAction(AutomationProgress progress) {
return createScriptAction(
getData().getParameters().getAction(), getData().getParameters(), progress);
public ScriptAction createScriptAction(AutomationProgress progress) {
return createScriptAction(getData().getParameters(), progress);
}

private static ScriptAction createScriptAction(
String action, ScriptJobParameters parameters, AutomationProgress progress) {
if (action == null) {
progress.error(
Constant.messages.getString(
"scripts.automation.error.actionNull", validActionsAsString()));
public static ScriptAction createScriptAction(
ScriptJobParameters parameters, AutomationProgress progress) {
if (parameters.getAction() == null) {
if (progress != null) {
progress.error(
Constant.messages.getString(
"scripts.automation.error.actionNull", validActionsAsString()));
}
return null;
}

action = action.toLowerCase();
String action = parameters.getAction().toLowerCase();
Function<ScriptJobParameters, ScriptAction> scriptActionFactory = ACTIONS.get(action);
if (scriptActionFactory != null) {
return scriptActionFactory.apply(parameters);
}

progress.error(
Constant.messages.getString(
"scripts.automation.error.actionNotDefined",
action,
validActionsAsString()));
if (progress != null) {
progress.error(
Constant.messages.getString(
"scripts.automation.error.actionNotDefined",
action,
validActionsAsString()));
}

return null;
}
Expand All @@ -182,7 +195,7 @@ public static List<String> validActions() {

public static List<String> validScriptTypesForAction(String action) {
ScriptAction scriptAction =
createScriptAction(action, new ScriptJobParameters(), new AutomationProgress());
createScriptAction(new ScriptJobParameters(action), new AutomationProgress());
if (scriptAction != null) {
return scriptAction.getSupportedScriptTypes();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,24 @@
public class ScriptJobParameters extends AutomationData {
private String action;
private String type;
private String engine;
private String name;
private String file;

public ScriptJobParameters() {}

public ScriptJobParameters(String action) {
this.action = action;
}

public ScriptJobParameters(
String action, String type, String engine, String name, String file) {
this.action = action;
this.type = type;
this.engine = engine;
this.name = name;
this.file = file;
}

public String getAction() {
return action;
Expand All @@ -42,11 +59,27 @@ public void setType(String type) {
this.type = type;
}

public String getEngine() {
return engine;
}

public void setEngine(String engine) {
this.engine = engine;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getFile() {
return file;
}

public void setFile(String file) {
this.file = file;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
/*
* Zed Attack Proxy (ZAP) and its related class files.
*
* ZAP is an HTTP/HTTPS proxy for assessing web application security.
*
* Copyright 2022 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.automation.actions;

import java.io.File;
import java.io.IOException;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import org.apache.commons.lang3.StringUtils;
import org.parosproxy.paros.Constant;
import org.zaproxy.addon.automation.AutomationEnvironment;
import org.zaproxy.addon.automation.AutomationProgress;
import org.zaproxy.zap.extension.script.ScriptEngineWrapper;
import org.zaproxy.zap.extension.script.ScriptWrapper;
import org.zaproxy.zap.extension.scripts.automation.ScriptJobParameters;

public class AddScriptAction extends ScriptAction {

public static final String NAME = "add";

public AddScriptAction(ScriptJobParameters parameters) {
super(parameters);
}

@Override
public String getName() {
return NAME;
}

@Override
public String getSummary() {
return Constant.messages.getString(
"scripts.automation.dialog.summary.add", parameters.getName());
}

@Override
public List<String> verifyParameters(
String jobName, ScriptJobParameters params, AutomationProgress progress) {
List<String> list = new ArrayList<>();
String issue;
String scriptType = parameters.getType();
String filename = params.getFile();

if (scriptType == null) {
issue =
Constant.messages.getString(
"scripts.automation.error.scriptTypeIsNull", jobName);
list.add(issue);
if (progress != null) {
progress.error(issue);
}
} else if (!this.isScriptTypeSupported()) {
issue =
Constant.messages.getString(
"scripts.automation.error.scriptTypeNotSupported",
jobName,
scriptType,
getName(),
String.join(", ", getSupportedScriptTypes()));
list.add(issue);
if (progress != null) {
progress.error(issue);
}
}

if (StringUtils.isEmpty(filename)) {
issue = Constant.messages.getString("scripts.automation.error.file.missing", jobName);
list.add(issue);
if (progress != null) {
progress.error(issue);
}
} else {
File f = new File(filename);
if (!f.canRead()) {
issue =
Constant.messages.getString(
"scripts.automation.error.file.cannotRead",
jobName,
f.getAbsolutePath());
list.add(issue);
if (progress != null) {
progress.error(issue);
}
} else if (!f.isFile()) {
issue =
Constant.messages.getString(
"scripts.automation.error.file.notFile",
jobName,
f.getAbsolutePath());
list.add(issue);
if (progress != null) {
progress.error(issue);
}
}
}

if (getEngineWrapper(params) == null) {
issue =
Constant.messages.getString(
"scripts.automation.error.scriptEngineNotFound",
jobName,
this.parameters.getEngine());
list.add(issue);
if (progress != null) {
progress.error(issue);
}
}

return list;
}

@Override
public List<String> getSupportedScriptTypes() {
return getAllScriptTypes();
}

@Override
public List<String> getDisabledFields() {
return Collections.emptyList();
}

private ScriptEngineWrapper getEngineWrapper(ScriptJobParameters params) {
ScriptEngineWrapper se = null;
try {
se = extScript.getEngineWrapper(this.parameters.getEngine());
} catch (Exception e) {
String filename = params.getFile();
if (filename != null && filename.contains(".")) {
try {
se =
extScript.getEngineWrapper(
extScript.getEngineNameForExtension(
filename.substring(filename.indexOf(".") + 1)
.toLowerCase(Locale.ROOT)));
} catch (InvalidParameterException e1) {
// Ignore - will return null below
}
}
}
return se;
}

private ScriptWrapper getScriptWrapper() {
ScriptWrapper sw = new ScriptWrapper();
sw.setName(this.parameters.getName());
if (this.parameters.getFile() != null) {
File f = new File(this.parameters.getFile());
sw.setFile(f);
if (StringUtils.isEmpty(sw.getName())) {
sw.setName(f.getName());
}
}
sw.setType(extScript.getScriptType(this.parameters.getType()));
sw.setEngine(getEngineWrapper(this.parameters));
sw.setEnabled(true);
return sw;
}

@Override
public void runJob(String jobName, AutomationEnvironment env, AutomationProgress progress) {
ScriptWrapper sw = this.getScriptWrapper();
try {
extScript.loadScript(sw);
ScriptWrapper existingScript = extScript.getScript(sw.getName());
if (existingScript != null) {
// Always replace an existing script with the same name
extScript.removeScript(existingScript);
progress.info(
Constant.messages.getString(
"scripts.automation.info.add.replace", jobName, sw.getName()));
}
extScript.addScript(sw);
} catch (IOException e) {
progress.error(
Constant.messages.getString(
"scripts.automation.error.add.failed", jobName, e.getMessage()));
}
}
}
Loading

0 comments on commit a80fee2

Please sign in to comment.