Skip to content

Commit

Permalink
Merge pull request #5445 from psiinon/scripts/loadDir
Browse files Browse the repository at this point in the history
Scripts: Add support for loadDir action
  • Loading branch information
kingthorin authored May 16, 2024
2 parents fc5f7e3 + 1c7d5f3 commit bf6eef6
Show file tree
Hide file tree
Showing 14 changed files with 344 additions and 53 deletions.
4 changes: 4 additions & 0 deletions addOns/scripts/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ All notable changes to this add-on will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## Unreleased
### Added
- Support for Automtion Framework loaddir action, which loads all of the scripts under the specified directory.

### Changed
- File parameter to `source`, `file` will still work.

## [45.3.0] - 2024-05-07
### Added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.zaproxy.zap.extension.scripts.automation.actions.AddScriptAction;
import org.zaproxy.zap.extension.scripts.automation.actions.DisableScriptAction;
import org.zaproxy.zap.extension.scripts.automation.actions.EnableScriptAction;
import org.zaproxy.zap.extension.scripts.automation.actions.LoadDirScriptAction;
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;
Expand All @@ -50,13 +51,16 @@ public class ScriptJob extends AutomationJob {
private static final long serialVersionUID = 1L;

{
put(AddScriptAction.NAME.toLowerCase(), AddScriptAction::new);
put(RemoveScriptAction.NAME.toLowerCase(), RemoveScriptAction::new);
put(RunScriptAction.NAME.toLowerCase(), RunScriptAction::new);
put(AddScriptAction.NAME.toLowerCase(Locale.ROOT), AddScriptAction::new);
put(RemoveScriptAction.NAME.toLowerCase(Locale.ROOT), RemoveScriptAction::new);
put(RunScriptAction.NAME.toLowerCase(Locale.ROOT), RunScriptAction::new);
put(EnableScriptAction.NAME.toLowerCase(Locale.ROOT), EnableScriptAction::new);
put(
DisableScriptAction.NAME.toLowerCase(Locale.ROOT),
DisableScriptAction::new);
put(
LoadDirScriptAction.NAME.toLowerCase(Locale.ROOT),
LoadDirScriptAction::new);
}
};

Expand Down Expand Up @@ -137,6 +141,11 @@ public ScriptJobData getData() {
return data;
}

@Override
public ScriptJobParameters getParameters() {
return parameters;
}

@Override
public Map<String, String> getCustomConfigParameters() {
Map<String, String> map = super.getCustomConfigParameters();
Expand Down Expand Up @@ -175,7 +184,7 @@ public static ScriptAction createScriptAction(
return null;
}

String action = parameters.getAction().toLowerCase();
String action = parameters.getAction().toLowerCase(Locale.ROOT);
Function<ScriptJobParameters, ScriptAction> scriptActionFactory = ACTIONS.get(action);
if (scriptActionFactory != null) {
return scriptActionFactory.apply(parameters);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public class ScriptJobParameters extends AutomationData {
private String type;
private String engine;
private String name;
private String file;
private String source;
private String target;
private String inline;

Expand All @@ -41,14 +41,14 @@ public ScriptJobParameters(
String type,
String engine,
String name,
String file,
String source,
String target,
String inline) {
this.action = action;
this.type = type;
this.engine = engine;
this.name = name;
this.file = file;
this.source = source;
this.target = target;
this.inline = inline;
}
Expand Down Expand Up @@ -85,12 +85,17 @@ public void setName(String name) {
this.name = name;
}

public String getFile() {
return file;
public String getSource() {
return source;
}

public void setSource(String source) {
this.source = source;
}

// For backwards compatibility
public void setFile(String file) {
this.file = file;
this.source = file;
}

public String getTarget() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public List<String> verifyParameters(
List<String> list = new ArrayList<>();
String issue;
String scriptType = parameters.getType();
String filename = params.getFile();
String filename = params.getSource();
String inline = params.getInline();

if (scriptType == null) {
Expand Down Expand Up @@ -171,7 +171,7 @@ private ScriptEngineWrapper getEngineWrapper(ScriptJobParameters params) {
try {
se = extScript.getEngineWrapper(this.parameters.getEngine());
} catch (Exception e) {
String filename = params.getFile();
String filename = params.getSource();
if (filename != null && filename.contains(".")) {
try {
se =
Expand All @@ -190,8 +190,8 @@ private ScriptEngineWrapper getEngineWrapper(ScriptJobParameters params) {
private ScriptWrapper getScriptWrapper(AutomationPlan plan) {
ScriptWrapper sw = new ScriptWrapper();
sw.setName(this.parameters.getName());
if (this.parameters.getFile() != null) {
File f = JobUtils.getFile(this.parameters.getFile(), plan);
if (this.parameters.getSource() != null) {
File f = JobUtils.getFile(this.parameters.getSource(), plan);
sw.setFile(f);
if (StringUtils.isEmpty(sw.getName())) {
sw.setName(f.getName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public List<String> verifyParameters(
}

// Note dont warn/error if script not currently in ZAP - it might be added by another job
if (!StringUtils.isEmpty(params.getFile())) {
if (!StringUtils.isEmpty(params.getSource())) {
issue =
Constant.messages.getString(
"scripts.automation.warn.fileNotNeeded", params.getName());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
/*
* 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.automation.actions;

import java.io.File;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
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.addon.automation.jobs.JobUtils;
import org.zaproxy.zap.extension.script.ScriptType;
import org.zaproxy.zap.extension.script.ScriptWrapper;
import org.zaproxy.zap.extension.scripts.automation.ScriptJobParameters;
import org.zaproxy.zap.extension.scripts.automation.ui.ScriptJobDialog;

public class LoadDirScriptAction extends ScriptAction {

public static final String NAME = "loaddir";
private static final List<String> DISABLED_FIELDS =
Arrays.asList(
ScriptJobDialog.SCRIPT_TYPE_PARAM,
ScriptJobDialog.SCRIPT_ENGINE_PARAM,
ScriptJobDialog.SCRIPT_NAME_PARAM,
ScriptJobDialog.SCRIPT_IS_INLINE_PARAM,
ScriptJobDialog.SCRIPT_TARGET_PARAM);

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

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

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

@Override
public List<String> verifyParameters(
String jobName, ScriptJobParameters params, AutomationProgress progress) {
List<String> list = new ArrayList<>();
String issue;
String path = params.getSource();

if (StringUtils.isEmpty(path)) {
issue = Constant.messages.getString("scripts.automation.error.file.missing", jobName);
list.add(issue);
if (progress != null) {
progress.error(issue);
}
} else if (JobUtils.isAbsoluteLiteralPath(path)) {
// Cannot check relative paths or ones that contain vars at this point
File f = new File(path);
if (JobUtils.isAbsoluteLiteralPath(path))
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.isDirectory()) {
issue =
Constant.messages.getString(
"scripts.automation.error.file.notDir",
jobName,
f.getAbsolutePath());
list.add(issue);
if (progress != null) {
progress.error(issue);
}
}
}

return list;
}

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

@Override
public List<String> getDisabledFields() {
return DISABLED_FIELDS;
}

private int addScriptsFromDir(
File dir, ScriptType type, String jobName, AutomationProgress progress) {
int addedScripts = 0;
File typeDir = new File(dir, type.getName());
if (typeDir.exists()) {
for (File f : typeDir.listFiles()) {
int dotIndex = f.getName().lastIndexOf(".");
if (dotIndex < 0) {
// Ignore files with no extension
continue;
}
String ext = f.getName().substring(dotIndex + 1);
String engineName = extScript.getEngineNameForExtension(ext);

if (engineName != null) {
StringWriter writer = new StringWriter();
try {
ScriptAction.getExtScript().addWriter(writer);

String scriptName = f.getName();
ScriptWrapper sw =
new ScriptWrapper(
scriptName,
"",
extScript.getEngineWrapper(engineName),
type,
true,
f);
extScript.loadScript(sw);
extScript.addScript(sw, false);
addedScripts++;

progress.info(
Constant.messages.getString(
"scripts.automation.info.loadDir.added",
jobName,
type.getName() + "/" + scriptName));

String scriptOutput = writer.toString();
if (scriptOutput.indexOf("Error") > 0) {
// A bit nasty, but no better options right now?
progress.error(
Constant.messages.getString(
"scripts.automation.info.script.output",
jobName,
writer.toString()));
} else if (scriptOutput.length() > 0) {
progress.info(
Constant.messages.getString(
"scripts.automation.info.script.output",
jobName,
writer.toString()));
}
} catch (Exception e) {
progress.error(
Constant.messages.getString(
"scripts.automation.error.loadDir.failed",
jobName,
f.getAbsolutePath(),
e.getMessage()));
} finally {
ScriptAction.getExtScript().removeWriter(writer);
}
} else {
LOGGER.debug("Ignoring {}", f.getName());
}
}
}
return addedScripts;
}

@Override
public void runJob(String jobName, AutomationEnvironment env, AutomationProgress progress) {
int addedScripts = 0;
File dir = new File(this.parameters.getSource());

for (ScriptType type : extScript.getScriptTypes()) {
addedScripts += addScriptsFromDir(dir, type, jobName, progress);
}
progress.info(
Constant.messages.getString(
"scripts.automation.info.loadDir.loaded",
jobName,
this.parameters.getSource(),
addedScripts));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public List<String> verifyParameters(
}

// Note dont warn/error if script not currently in ZAP - it might be added by another job
if (!StringUtils.isEmpty(params.getFile())) {
if (!StringUtils.isEmpty(params.getSource())) {
issue =
Constant.messages.getString(
"scripts.automation.warn.fileNotNeeded", params.getName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public List<String> verifyParameters(
}
}
// Note dont warn/error if script not currently in ZAP - it might be added by another job
if (!StringUtils.isEmpty(params.getFile())) {
if (!StringUtils.isEmpty(params.getSource())) {
issue =
Constant.messages.getString(
"scripts.automation.warn.fileNotNeeded", params.getName());
Expand Down Expand Up @@ -158,7 +158,7 @@ private ScriptEngineWrapper getEngineWrapper(ScriptJobParameters params) {
try {
se = extScript.getEngineWrapper(this.parameters.getEngine());
} catch (Exception e) {
String filename = params.getFile();
String filename = params.getSource();
if (filename != null && filename.contains(".")) {
try {
se =
Expand Down
Loading

0 comments on commit bf6eef6

Please sign in to comment.