org.parosproxy.paros.CommandLine Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of zap Show documentation
Show all versions of zap Show documentation
The Zed Attack Proxy (ZAP) is an easy to use integrated penetration testing tool for finding vulnerabilities in web applications. It is designed to be used by people with a wide range of security experience and as such is ideal for developers and functional testers who are new to penetration testing. ZAP provides automated scanners as well as a set of tools that allow you to find security vulnerabilities manually.
/*
*
* 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/04/16 Support for running ZAP as a daemon
// ZAP: 2012/03/15 Removed unnecessary castings from methods parse, getArgument and getHelp.
// Changed to use the class StringBuilder instead of the class StringBuffer in the method getHelp.
// ZAP: 2012/10/15 Issue 397: Support weekly builds
// ZAP: 2013/03/03 Issue 546: Remove all template Javadoc comments
// ZAP: 2013/03/20 Issue 568: Allow extensions to run from the command line
// ZAP: 2013/08/30 Issue 775: Allow host to be set via the command line
// ZAP: 2013/12/03 Issue 933: Automatically determine install dir
// ZAP: 2013/12/03 Issue 934: Handle files on the command line via extension
// ZAP: 2014/01/17 Issue 987: Allow arbitrary config file values to be set via the command line
// ZAP: 2014/05/20 Issue 1191: Cmdline session params have no effect
// ZAP: 2015/04/02 Issue 321: Support multiple databases and Issue 1582: Low memory option
// ZAP: 2015/10/06 Issue 1962: Install and update add-ons from the command line
// ZAP: 2016/08/19 Issue 2782: Support -configfile
// ZAP: 2016/09/22 JavaDoc tweaks
// ZAP: 2016/11/07 Allow to disable default standard output logging
// ZAP: 2017/03/26 Allow to obtain configs in the order specified
// ZAP: 2017/05/12 Issue 3460: Support -suppinfo
// ZAP: 2017/05/31 Handle null args and include a message in all exceptions.
// ZAP: 2017/08/31 Use helper method I18N.getString(String, Object...).
// ZAP: 2017/11/21 Validate that -cmd and -daemon are not set at the same time (they are mutually exclusive).
package org.parosproxy.paros;
import java.io.File;
import java.io.FileInputStream;
import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import org.apache.log4j.Logger;
import org.parosproxy.paros.extension.CommandLineArgument;
import org.parosproxy.paros.extension.CommandLineListener;
import org.parosproxy.paros.network.HttpSender;
import org.zaproxy.zap.ZAP;
public class CommandLine {
private static final Logger logger = Logger.getLogger(CommandLine.class);
// ZAP: Made public
public static final String SESSION = "-session";
public static final String NEW_SESSION = "-newsession";
public static final String DAEMON = "-daemon";
public static final String HELP = "-help";
public static final String HELP2 = "-h";
public static final String DIR = "-dir";
public static final String VERSION = "-version";
public static final String PORT = "-port";
public static final String HOST = "-host";
public static final String CMD = "-cmd";
public static final String INSTALL_DIR = "-installdir";
public static final String CONFIG = "-config";
public static final String CONFIG_FILE = "-configfile";
public static final String LOWMEM = "-lowmem";
public static final String EXPERIMENTALDB = "-experimentaldb";
public static final String SUPPORT_INFO = "-suppinfo";
/**
* Command line option to disable the default logging through standard output.
*
* @see #isNoStdOutLog()
* @since 2.6.0
*/
public static final String NOSTDOUT = "-nostdout";
static final String NO_USER_AGENT = "-nouseragent";
static final String SP = "-sp";
private boolean GUI = true;
private boolean daemon = false;
private boolean reportVersion = false;
private boolean displaySupportInfo = false;
private boolean lowMem = false;
private boolean experimentalDb = false;
private int port = -1;
private String host = null;
private String[] args;
private final Map configs = new LinkedHashMap<>();
private final Hashtable keywords = new Hashtable<>();
private List commandList = null;
/**
* Flag that indicates whether or not the default logging through standard output should be disabled.
*/
private boolean noStdOutLog;
public CommandLine(String[] args) throws Exception {
this.args = args == null ? new String[0] : args;
parseFirst(this.args);
if (isEnabled(CommandLine.CMD) && isEnabled(CommandLine.DAEMON)) {
throw new IllegalArgumentException(
"Command line arguments " + CommandLine.CMD + " and " + CommandLine.DAEMON
+ " cannot be used at the same time.");
}
}
private boolean checkPair(String[] args, String paramName, int i) throws Exception {
String key = args[i];
String value = null;
if (key == null) {
return false;
}
if (key.equalsIgnoreCase(paramName)) {
value = args[i + 1];
if (value == null) {
throw new Exception("Missing parameter for keyword '" + paramName + "'.");
}
keywords.put(paramName, value);
args[i] = null;
args[i + 1] = null;
return true;
}
return false;
}
private boolean checkSwitch(String[] args, String paramName, int i) throws Exception {
String key = args[i];
if (key == null) {
return false;
}
if (key.equalsIgnoreCase(paramName)) {
keywords.put(paramName, "");
args[i] = null;
return true;
}
return false;
}
private void parseFirst(String[] args) throws Exception {
for (int i = 0; i < args.length; i++) {
if (parseSwitchs(args, i)) {
continue;
}
if (parseKeywords(args, i)) {
continue;
}
}
}
public void parse(List commandList, Map extMap) throws Exception {
this.commandList = commandList;
CommandLineArgument lastArg = null;
boolean found = false;
int remainingValueCount = 0;
for (int i = 0; i < args.length; i++) {
if (args[i] == null) {
continue;
}
found = false;
for (int j = 0; j < commandList.size() && !found; j++) {
CommandLineArgument[] extArg = commandList.get(j);
for (int k = 0; k < extArg.length && !found; k++) {
if (args[i].compareToIgnoreCase(extArg[k].getName()) == 0) {
// check if previous keyword satisfied its required no. of parameters
if (remainingValueCount > 0) {
throw new Exception("Missing parameters for keyword '" + lastArg.getName() + "'.");
}
// process this keyword
lastArg = extArg[k];
lastArg.setEnabled(true);
found = true;
args[i] = null;
remainingValueCount = lastArg.getNumOfArguments();
}
}
}
// check if current string is a keyword preceded by '-'
if (args[i] != null && args[i].startsWith("-")) {
continue;
}
// check if there is no more expected param value
if (lastArg != null && remainingValueCount == 0) {
continue;
}
// check if consume remaining for last matched keywords
if (!found && lastArg != null) {
if (lastArg.getPattern() == null || lastArg.getPattern().matcher(args[i]).find()) {
lastArg.getArguments().add(args[i]);
if (remainingValueCount > 0) {
remainingValueCount--;
}
args[i] = null;
} else {
throw new Exception(lastArg.getErrorMessage());
}
}
}
// check if the last keyword satified its no. of parameters.
if (lastArg != null && remainingValueCount > 0) {
throw new Exception("Missing parameters for keyword '" + lastArg.getName() + "'.");
}
// check for supported extensions
for (int i = 0; i < args.length; i++) {
if (args[i] == null) {
continue;
}
int dotIndex = args[i].lastIndexOf(".");
if (dotIndex < 0) {
// Only support files with extensions
continue;
}
File file = new File(args[i]);
if (!file.exists() || !file.canRead()) {
// Not there or cant read .. move on
continue;
}
String ext = args[i].substring(dotIndex + 1);
CommandLineListener cll = extMap.get(ext);
if (cll != null) {
if (cll.handleFile(file)) {
found = true;
args[i] = null;
}
}
}
// check if there is some unknown keywords or parameters
for (String arg : args) {
if (arg != null) {
if (arg.startsWith("-")) {
throw new Exception(Constant.messages.getString("start.cmdline.badparam", arg));
} else {
// Assume they were trying to specify a file
File f = new File(arg);
if (!f.exists()) {
throw new Exception(Constant.messages.getString("start.cmdline.nofile", arg));
} else if (!f.canRead()) {
throw new Exception(Constant.messages.getString("start.cmdline.noread", arg));
} else {
// We probably dont handle this sort of file
throw new Exception(Constant.messages.getString("start.cmdline.badfile", arg));
}
}
}
}
}
private boolean parseSwitchs(String[] args, int i) throws Exception {
boolean result = false;
if (checkSwitch(args, NO_USER_AGENT, i)) {
HttpSender.setUserAgent("");
Constant.setEyeCatcher("");
result = true;
} else if (checkSwitch(args, SP, i)) {
Constant.setSP(true);
result = true;
} else if (checkSwitch(args, CMD, i)) {
setDaemon(false);
setGUI(false);
} else if (checkSwitch(args, DAEMON, i)) {
setDaemon(true);
setGUI(false);
} else if (checkSwitch(args, LOWMEM, i)) {
setLowMem(true);
} else if (checkSwitch(args, EXPERIMENTALDB, i)) {
setExperimentalDb(true);
} else if (checkSwitch(args, HELP, i)) {
result = true;
setGUI(false);
} else if (checkSwitch(args, HELP2, i)) {
result = true;
setGUI(false);
} else if (checkSwitch(args, VERSION, i)) {
reportVersion = true;
setDaemon(false);
setGUI(false);
} else if (checkSwitch(args, NOSTDOUT, i)) {
noStdOutLog = true;
} else if (checkSwitch(args, SUPPORT_INFO, i)) {
displaySupportInfo = true;
setDaemon(false);
setGUI(false);
}
return result;
}
private boolean parseKeywords(String[] args, int i) throws Exception {
boolean result = false;
if (checkPair(args, NEW_SESSION, i)) {
result = true;
} else if (checkPair(args, SESSION, i)) {
result = true;
} else if (checkPair(args, DIR, i)) {
Constant.setZapHome(keywords.get(DIR));
result = true;
} else if (checkPair(args, INSTALL_DIR, i)) {
Constant.setZapInstall(keywords.get(INSTALL_DIR));
result = true;
} else if (checkPair(args, HOST, i)) {
this.host = keywords.get(HOST);
result = true;
} else if (checkPair(args, PORT, i)) {
this.port = Integer.parseInt(keywords.get(PORT));
result = true;
} else if (checkPair(args, CONFIG, i)) {
String pair = keywords.get(CONFIG);
if (pair != null && pair.indexOf("=") > 0) {
int eqIndex = pair.indexOf("=");
this.configs.put(pair.substring(0, eqIndex), pair.substring(eqIndex + 1));
result = true;
}
} else if (checkPair(args, CONFIG_FILE, i)) {
String conf = keywords.get(CONFIG_FILE);
File confFile = new File(conf);
if (! confFile.isFile()) {
// We cant use i18n here as the messages wont have been loaded
throw new Exception("No such file: " + confFile.getAbsolutePath());
} else if (! confFile.canRead()) {
// We cant use i18n here as the messages wont have been loaded
throw new Exception("File not readable: " + confFile.getAbsolutePath());
}
Properties prop = new Properties();
try (FileInputStream inStream = new FileInputStream(confFile)) {
prop.load(inStream);
}
for (Entry