org.parosproxy.paros.Constant Maven / Gradle / Ivy
Show all versions of zap Show documentation
/*
* Created on May 18, 2004
*
* Paros and its related class files.
*
* Paros is an HTTP/HTTPS proxy for assessing web application security.
* Copyright (C) 2003-2005 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/03 Revamped upgrade for 1.3.2
// ZAP: 2011/10/05 Write backup file to user dir
// ZAP: 2011/11/15 Changed to use ZapXmlConfiguration, to enforce the same
// character encoding when reading/writing configurations. Changed to use the
// correct file when an error occurs during the load of the configuration file.
// Removed the calls XMLConfiguration.load() as they are not needed, the
// XMLConfiguration constructor used already does that.
// ZAP: 2011/11/20 Support for extension factory
// ZAP: 2012/03/03 Added ZAP homepage
// ZAP: 2012/03/15 Removed a @SuppressWarnings annotation from the method
// copyAllProperties.
// ZAP: 2012/03/17 Issue 282 ZAP and PAROS team constants
// ZAP: 2012/05/02 Added method createInstance and changed the method
// getInstance to use it.
// ZAP: 2012/05/03 Changed the Patterns used to detect the O.S. to be final.
// ZAP: 2012/06/15 Issue 312 Increase the maximum number of scanning threads allowed
// ZAP: 2012/07/13 Added variable for maximum number of threads used in scan (MAX_THREADS_PER_SCAN)
// ZAP: 2012/10/15 Issue 397: Support weekly builds
// ZAP: 2012/10/17 Issue 393: Added more online links from menu
// ZAP: 2012/11/15 Issue 416: Normalise how multiple related options are managed
// throughout ZAP and enhance the usability of some options.
// ZAP: 2012/11/20 Issue 419: Restructure jar loading code
// ZAP: 2012/12/08 Issue 428: Changed to use I18N for messages, to support the marketplace
// ZAP: 2013/03/03 Issue 546: Remove all template Javadoc comments
// ZAP: 2013/04/14 Issue 610: Replace the use of the String class for available/default "Forced
// Browse" files
// ZAP: 2013/04/15 Issue 632: Manual Request Editor dialogue (HTTP) configurations not saved
// correctly
// ZAP: 2013/12/03 Issue 933: Automatically determine install dir
// ZAP: 2013/12/13 Issue 919: Support for multiple language vulnerability files.
// ZAP: 2014/04/11 Issue 1148: ZAP 2.3.0 does not launch after upgrading in some situations
// ZAP: 2014/07/15 Issue 1265: Context import and export
// ZAP: 2014/08/14 Issue 1300: Add-ons show incorrect language when English is selected on non
// English locale
// ZAP: 2014/11/11 Issue 1406: Move online menu items to an add-on
// ZAP: 2015/01/04 Issue 1388: Not all translated files are updated when "zaplang" package is
// imported
// ZAP: 2014/01/04 Issue 1394: Import vulnerabilities.xml files when updating the translated
// resources
// ZAP: 2014/01/04 Issue 1458: Change home/installation dir paths to be always absolute
// ZAP: 2015/03/10 Issue 653: Handle updates on Kali better
// ZAP: 2015/03/30 Issue 1582: Enablers for low memory option
// ZAP: 2015/04/12 Remove "installation" fuzzers dir, no longer in use
// ZAP: 2015/08/01 Remove code duplication in catch of exceptions, use installation directory in
// default config file
// ZAP: 2015/11/11 Issue 2045: Dont copy old configs if -dir option used
// ZAP: 2015/11/26 Issue 2084: Warn users if they are probably using out of date versions
// ZAP: 2016/02/17 Convert extensions' options to not use extensions' names as XML element names
// ZAP: 2016/05/12 Use dev/weekly dir for plugin downloads when copying the existing 'release'
// config file
// ZAP: 2016/06/07 Remove commented constants and statement that had no (actual) effect, add doc to
// a constant and init other
// ZAP: 2016/06/07 Use filter directory in ZAP's home directory
// ZAP: 2016/06/13 Migrate config option "proxy.modifyAcceptEncoding"
// ZAP: 2016/07/07 Convert passive scanners options to new structure
// ZAP: 2016/09/22 JavaDoc tweaks
// ZAP: 2016/11/17 Issue 2701 Support Factory Reset
// ZAP: 2017/05/04 Issue 3440: Log Exception when overwriting a config file
// ZAP: 2017/12/26 Remove class methods no longer used.
// ZAP: 2018/01/03 No longer create filter dir and deprecate FOLDER_FILTER constant.
// Exit immediately if not able to create the home dir.
// ZAP: 2018/01/04 Clear SNI Terminator options when updating from older ZAP versions.
// ZAP: 2018/01/05 Prevent use of install dir as home dir.
// ZAP: 2018/02/14 Remove unnecessary boxing / unboxing
// ZAP: 2018/03/16 Use equalsIgnoreCase (Issue 4327).
// ZAP: 2018/04/16 Keep backup of malformed config file.
// ZAP: 2018/06/13 Correct install dir detection from JAR.
// ZAP: 2018/06/29 Allow to check if in dev mode.
// ZAP: 2018/07/19 Fallback to bundled config.xml and log4j.properties.
// ZAP: 2019/03/14 Move and correct update of old options.
// ZAP: 2019/04/01 Refactored to reduce code-duplication.
// ZAP: 2019/05/10 Apply installer config options on update.
// Fix exceptions during config update.
// ZAP: 2019/05/14 Added silent option
// ZAP: 2019/05/17 Update cert option to boolean.
// ZAP: 2019/05/29 Update Jericho log configuration.
// ZAP: 2019/06/01 Normalise line endings.
// ZAP: 2019/06/05 Normalise format/style.
// ZAP: 2019/06/07 Update current version.
// ZAP: 2019/09/16 Deprecate ZAP_HOMEPAGE and ZAP_EXTENSIONS_PAGE.
// ZAP: 2019/11/07 Removed constants related to accepting the license.
// ZAP: 2020/01/02 Updated config version and default user agent
// ZAP: 2020/01/06 Set latest version to default config.
// ZAP: 2020/01/10 Correct the MailTo autoTagScanner regex pattern when upgrading from 2.8 or
// earlier.
// ZAP: 2020/04/22 Check ControlOverrides when determining the locale.
// ZAP: 2020/09/17 Correct the Syntax Highlighting markoccurrences config key name when upgrading
// from 2.9 or earlier.
// ZAP: 2020/10/07 Changes for Log4j 2 migration.
// ZAP: 2020/11/02 Do not backup old Log4j config if already present.
// ZAP: 2020/11/26 Use Log4j 2 classes for logging.
// ZAP: 2021/09/15 Added support for detecting containers
// ZAP: 2021/09/21 Added support for detecting snapcraft
// ZAP: 2021/10/01 Added support for detecting WebSwing
// ZAP: 2021/10/06 Update user agent when upgrading from 2.10
// ZAP: 2022/02/03 Removed deprecated FILE_CONFIG_DEFAULT and VULNS_BASE
// ZAP: 2022/02/25 Remove options that are no longer needed.
// ZAP: 2022/05/20 Remove usage of ConnectionParam.
// ZAP: 2022/09/21 Use format specifiers instead of concatenation when logging.
// ZAP: 2022/12/22 Issue 7663: Default threads based on number of processors.
// ZAP: 2023/01/10 Tidy up logger.
// ZAP: 2023/08/07 Rename home dir in Windows and update program name.
// ZAP: 2023/08/21 Deprecate vulnerabilities constants.
// ZAP: 2023/08/28 Update paths in config file to match the renamed home dir.
// ZAP: 2023/09/14 Lock home directory.
// ZAP: 2024/04/25 Add new autoTagScanner regex patterns when upgrading from 2.14 or earlier.
package org.parosproxy.paros;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.security.InvalidParameterException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.NoSuchElementException;
import java.util.Properties;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.ConversionException;
import org.apache.commons.configuration.HierarchicalConfiguration;
import org.apache.commons.configuration.XMLConfiguration;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.config.Configurator;
import org.parosproxy.paros.extension.option.OptionsParamView;
import org.parosproxy.paros.model.FileCopier;
import org.parosproxy.paros.model.Model;
import org.zaproxy.zap.ZAP;
import org.zaproxy.zap.control.AddOnLoader;
import org.zaproxy.zap.control.ControlOverrides;
import org.zaproxy.zap.extension.autoupdate.OptionsParamCheckForUpdates;
import org.zaproxy.zap.utils.I18N;
import org.zaproxy.zap.utils.ZapXmlConfiguration;
public final class Constant {
// ZAP: rebrand
public static final String PROGRAM_NAME = "ZAP";
public static final String PROGRAM_NAME_SHORT = "ZAP";
/**
* @deprecated (2.9.0) Do not use, it will be removed.
*/
@Deprecated public static final String ZAP_HOMEPAGE = "http://www.owasp.org/index.php/ZAP";
/**
* @deprecated (2.9.0) Do not use, it will be removed.
*/
@Deprecated
public static final String ZAP_EXTENSIONS_PAGE = "https://github.com/zaproxy/zap-extensions";
public static final String ZAP_TEAM = "ZAP Dev Team";
public static final String PAROS_TEAM = "Chinotec Technologies";
// ************************************************************
// the config.xml MUST be set to be the same as the version_tag
// otherwise the config.xml will be overwritten everytime.
// ************************************************************
private static final String DEV_VERSION = "Dev Build";
public static final String ALPHA_VERSION = "alpha";
public static final String BETA_VERSION = "beta";
private static final String VERSION_ELEMENT = "version";
// Accessible for tests
static final long VERSION_TAG = 20015000;
// Old version numbers - for upgrade
private static final long V_2_14_0_TAG = 20014000;
private static final long V_2_12_0_TAG = 20012000;
private static final long V_2_11_1_TAG = 20011001;
private static final long V_2_9_0_TAG = 2009000;
private static final long V_2_8_0_TAG = 2008000;
private static final long V_2_7_0_TAG = 2007000;
private static final long V_2_5_0_TAG = 2005000;
private static final long V_2_4_3_TAG = 2004003;
private static final long V_2_3_1_TAG = 2003001;
private static final long V_2_2_2_TAG = 2002002;
private static final long V_2_2_0_TAG = 2002000;
private static final long V_2_1_0_TAG = 2001000;
private static final long V_2_0_0_TAG = 2000000;
private static final long V_1_4_1_TAG = 1004001;
private static final long V_1_3_1_TAG = 1003001;
private static final long V_1_3_0_TAG = 1003000;
private static final long V_1_2_1_TAG = 1002001;
private static final long V_1_2_0_TAG = 1002000;
private static final long V_1_1_0_TAG = 1001000;
private static final long V_1_0_0_TAG = 1000000;
private static final long V_PAROS_TAG = 30020013;
// ************************************************************
// note the above
// ************************************************************
// These are no longer final - version is now loaded from the manifest file
public static String PROGRAM_VERSION = DEV_VERSION;
public static String PROGRAM_TITLE = PROGRAM_NAME + " " + PROGRAM_VERSION;
public static final String SYSTEM_PAROS_USER_LOG = "zap.user.log";
public static final String FILE_SEPARATOR = System.getProperty("file.separator");
public static final String FILE_CONFIG_NAME = "config.xml";
public static final String FOLDER_PLUGIN = "plugin";
/**
* The name of the directory for filter related files (the path should be built using {@link
* #getZapHome()} as the parent directory).
*
* @deprecated (2.8.0) Should not be used, the filter functionality is deprecated (replaced by
* scripts and Replacer add-on).
* @since 1.0.0
*/
@Deprecated public static final String FOLDER_FILTER = "filter";
/**
* The name of the directory where the (file) sessions are saved by default.
*
* @since 1.0.0
*/
public static final String FOLDER_SESSION_DEFAULT = "session";
public static final String DBNAME_TEMPLATE =
"db" + System.getProperty("file.separator") + "zapdb";
/**
* Prefix (file name) of Messages.properties files.
*
* @see #MESSAGES_EXTENSION
*/
public static final String MESSAGES_PREFIX = "Messages";
/**
* Extension (with dot) of Messages.properties files.
*
* @see #MESSAGES_PREFIX
* @since 2.4.0
*/
public static final String MESSAGES_EXTENSION = ".properties";
public static final String DBNAME_UNTITLED_DEFAULT =
FOLDER_SESSION_DEFAULT + System.getProperty("file.separator") + "untitled";
public String FILE_CONFIG = FILE_CONFIG_NAME;
public String FOLDER_SESSION = FOLDER_SESSION_DEFAULT;
public String DBNAME_UNTITLED =
FOLDER_SESSION + System.getProperty("file.separator") + "untitled";
public static final String FILE_PROGRAM_SPLASH = "resource/zap128x128.png";
// Accelerator keys - Default: Windows
public static String ACCELERATOR_UNDO = "control Z";
public static String ACCELERATOR_REDO = "control Y";
public static String ACCELERATOR_TRIGGER_KEY = "Control";
private static Constant instance = null;
public static final int MAX_HOST_CONNECTION = 15;
@Deprecated // No longer limit in the UI
public static final int MAX_THREADS_PER_SCAN = 50;
// ZAP: Dont announce ourselves
// public static final String USER_AGENT = PROGRAM_NAME + "/" + PROGRAM_VERSION;
public static final String USER_AGENT = "";
private static String staticEyeCatcher = "0W45pz4p";
private static final String USER_CONTEXTS_DIR = "contexts";
private static final String USER_POLICIES_DIR = "policies";
private static final String ZAP_CONTAINER_FILE = "/zap/container";
private static final String FLATPAK_FILE = "/.flatpak-info";
public static final String FLATPAK_NAME = "flatpak";
private static final String SNAP_FILE = "meta/snap.yaml";
public static final String SNAP_NAME = "snapcraft";
private static final String HOME_ENVVAR = "HOME";
public static final String WEBSWING_NAME = "webswing";
//
// Home dir for ZAP, i.e. where the config file is. Can be set on cmdline, otherwise will be set
// to default loc
private static String zapHome = null;
// Default home dir for 'full' releases - used for copying full conf file when dev/daily release
// run for the first time
// and also for the JVM options config file
private static String zapStd = null;
// Install dir for ZAP, but default will be cwd
private static String zapInstall = null;
private static Boolean onKali = null;
private static Boolean onBackBox = null;
private static Boolean inContainer = null;
private static String containerName;
private static Boolean lowMemoryOption = null;
// ZAP: Added i18n
public static I18N messages = null;
/**
* The system's locale (as determined by the JVM at startup, {@code Locale#getDefault()}).
*
* The locale is kept here because the default locale is later overridden with the user's
* chosen locale/language.
*
* @see Locale#getDefault()
*/
private static final Locale SYSTEMS_LOCALE = Locale.getDefault();
/** The path to bundled (in zap.jar) config.xml file. */
private static final String PATH_BUNDLED_CONFIG_XML =
"/org/zaproxy/zap/resources/" + FILE_CONFIG_NAME;
/**
* Name of directory that contains the (source and translated) resource files.
*
* @see #MESSAGES_PREFIX
* @see #VULNERABILITIES_PREFIX
*/
public static final String LANG_DIR = "lang";
/**
* Prefix (file name) of vulnerabilities.xml files.
*
* @see #VULNERABILITIES_EXTENSION
* @deprecated (2.14.0) The vulnerabilities were moved to Common Library add-on.
* @since 2.4.0
*/
@Deprecated(since = "2.14.0", forRemoval = true)
public static final String VULNERABILITIES_PREFIX = "vulnerabilities";
/**
* Extension (with dot) of vulnerabilities.xml files.
*
* @see #VULNERABILITIES_PREFIX
* @deprecated (2.14.0) The vulnerabilities were moved to Common Library add-on.
* @since 2.4.0
*/
@Deprecated(since = "2.14.0", forRemoval = true)
public static final String VULNERABILITIES_EXTENSION = ".xml";
/**
* Flag that indicates whether or not the "dev mode" is enabled.
*
* @see #isDevMode()
*/
private static boolean devMode;
private static boolean silent;
// ZAP: Added dirbuster dir
public String DIRBUSTER_DIR = "dirbuster";
public String DIRBUSTER_CUSTOM_DIR = DIRBUSTER_DIR;
public String FUZZER_DIR = "fuzzers";
public static String FOLDER_LOCAL_PLUGIN = FOLDER_PLUGIN;
public static final URL OK_FLAG_IMAGE_URL =
Constant.class.getResource("/resource/icon/10/072.png"); // Green
public static final URL INFO_FLAG_IMAGE_URL =
Constant.class.getResource("/resource/icon/10/073.png"); // Blue
public static final URL LOW_FLAG_IMAGE_URL =
Constant.class.getResource("/resource/icon/10/074.png"); // Yellow
public static final URL MED_FLAG_IMAGE_URL =
Constant.class.getResource("/resource/icon/10/076.png"); // Orange
public static final URL HIGH_FLAG_IMAGE_URL =
Constant.class.getResource("/resource/icon/10/071.png"); // Red
public static final URL BLANK_IMAGE_URL =
Constant.class.getResource("/resource/icon/10/blank.png");
public static final URL SPIDER_IMAGE_URL =
Constant.class.getResource("/resource/icon/10/spider.png");
private static final Logger LOGGER = LogManager.getLogger(Constant.class);
private FileChannel homeLockFileChannel;
private FileLock homeLock;
public static String getEyeCatcher() {
return staticEyeCatcher;
}
public static void setEyeCatcher(String eyeCatcher) {
staticEyeCatcher = eyeCatcher;
}
public Constant() {
this(null);
}
private Constant(ControlOverrides overrides) {
initializeFilesAndDirectories(overrides);
setAcceleratorKeys();
}
public static String getDefaultHomeDirectory(boolean incDevOption) {
if (zapStd == null) {
zapStd = getUserHome();
if (isLinux()) {
// Linux: Hidden Zap directory in the user's home directory
zapStd += FILE_SEPARATOR + "." + PROGRAM_NAME_SHORT;
} else if (isMacOsX()) {
// Mac Os X: Support for writing the configuration into the users Library
zapStd +=
FILE_SEPARATOR
+ "Library"
+ FILE_SEPARATOR
+ "Application Support"
+ FILE_SEPARATOR
+ PROGRAM_NAME_SHORT;
} else {
// Windows: Zap directory in the user's home directory
zapStd += FILE_SEPARATOR + PROGRAM_NAME_SHORT;
}
}
if (incDevOption) {
if (isDevMode() || isDailyBuild()) {
// Default to a different home dir to prevent messing up full releases
return zapStd + "_D";
}
}
return zapStd;
}
/**
* Gets the user home.
*
*
It is returned the system property {@code user.home} if defined otherwise the current
* directory (i.e. {@code "."}).
*
* @return the user home, or the current directory.
*/
private static String getUserHome() {
String home = System.getProperty("user.home");
if (home == null) {
return ".";
}
return home;
}
public void copyDefaultConfigs(File f, boolean forceReset)
throws IOException, ConfigurationException {
FileCopier copier = new FileCopier();
File oldf;
if (isDevMode() || isDailyBuild()) {
// try standard location
oldf = new File(getDefaultHomeDirectory(false) + FILE_SEPARATOR + FILE_CONFIG_NAME);
} else {
// try old location
oldf = new File(zapHome + FILE_SEPARATOR + "zap" + FILE_SEPARATOR + FILE_CONFIG_NAME);
}
if (!forceReset
&& oldf.exists()
&& Paths.get(zapHome).equals(Paths.get(getDefaultHomeDirectory(true)))) {
// Dont copy old configs if forcedReset or they've specified a non std directory
LOGGER.info("Copying defaults from {} to {}", oldf.getAbsolutePath(), FILE_CONFIG);
copier.copy(oldf, f);
if (isDevMode() || isDailyBuild()) {
ZapXmlConfiguration newConfig = new ZapXmlConfiguration(f);
newConfig.setProperty(
OptionsParamCheckForUpdates.DOWNLOAD_DIR, Constant.FOLDER_LOCAL_PLUGIN);
newConfig.save();
}
} else {
LOGGER.info("Copying default configuration to {}", FILE_CONFIG);
copyDefaultConfigFile();
}
}
private void copyDefaultConfigFile() throws IOException {
Path configFile = Paths.get(FILE_CONFIG);
copyFileToHome(configFile, "xml/" + FILE_CONFIG_NAME, PATH_BUNDLED_CONFIG_XML);
try {
setLatestVersion(new ZapXmlConfiguration(configFile.toFile()));
} catch (ConfigurationException e) {
throw new IOException("Failed to set the latest version:", e);
}
}
/**
* Sets the latest version ({@link #VERSION_TAG}) to the given configuration and then saves it.
*
* @param config the configuration to change
* @throws ConfigurationException if an error occurred while saving the configuration.
*/
private static void setLatestVersion(XMLConfiguration config) throws ConfigurationException {
config.setProperty(VERSION_ELEMENT, VERSION_TAG);
config.save();
}
private static void copyFileToHome(
Path targetFile, String sourceFilePath, String fallbackResource) throws IOException {
Path defaultConfig = Paths.get(getZapInstall(), sourceFilePath);
if (Files.exists(defaultConfig)) {
Files.copy(defaultConfig, targetFile, StandardCopyOption.REPLACE_EXISTING);
} else {
try (InputStream is = Constant.class.getResourceAsStream(fallbackResource)) {
if (is == null) {
throw new IOException("Bundled resource not found: " + fallbackResource);
}
Files.copy(is, targetFile, StandardCopyOption.REPLACE_EXISTING);
}
}
}
private static URL getUrlDefaultConfigFile() {
Path path = getPathDefaultConfigFile();
if (Files.exists(path)) {
try {
return path.toUri().toURL();
} catch (MalformedURLException e) {
LOGGER.debug("Failed to convert file system path:", e);
}
}
return Constant.class.getResource(PATH_BUNDLED_CONFIG_XML);
}
public void initializeFilesAndDirectories() {
initializeFilesAndDirectories(null);
}
private void initializeFilesAndDirectories(ControlOverrides overrides) {
FileCopier copier = new FileCopier();
File f = null;
// Set up the version from the manifest
PROGRAM_VERSION = getVersionFromManifest();
PROGRAM_TITLE = PROGRAM_NAME + " " + PROGRAM_VERSION;
if (zapHome == null) {
renameOldWindowsHome();
zapHome = getDefaultHomeDirectory(true);
}
zapHome = getAbsolutePath(zapHome);
f = new File(zapHome);
FILE_CONFIG = zapHome + FILE_CONFIG;
FOLDER_SESSION = zapHome + FOLDER_SESSION;
DBNAME_UNTITLED = zapHome + DBNAME_UNTITLED;
DIRBUSTER_CUSTOM_DIR = zapHome + DIRBUSTER_DIR;
FUZZER_DIR = zapHome + FUZZER_DIR;
FOLDER_LOCAL_PLUGIN = zapHome + FOLDER_PLUGIN;
try {
System.setProperty(SYSTEM_PAROS_USER_LOG, zapHome);
if (!f.isDirectory()) {
if (f.exists()) {
System.err.println("The home path is not a directory: " + zapHome);
System.exit(1);
}
if (!f.mkdir()) {
System.err.println("Unable to create home directory: " + zapHome);
System.err.println("Is the path correct and there's write permission?");
System.exit(1);
}
} else if (!f.canWrite()) {
System.err.println("The home path is not writable: " + zapHome);
System.exit(1);
} else {
Path installDir = Paths.get(getZapInstall()).toRealPath();
if (installDir.equals(Paths.get(zapHome).toRealPath())) {
System.err.println(
"The install dir should not be used as home dir: " + installDir);
System.exit(1);
}
}
if (!acquireHomeLock()) {
System.exit(1);
}
setUpLogging();
f = new File(FILE_CONFIG);
if (!f.isFile()) {
this.copyDefaultConfigs(f, false);
}
f = new File(FOLDER_SESSION);
if (!f.isDirectory()) {
LOGGER.info("Creating directory {}", FOLDER_SESSION);
if (!f.mkdir()) {
// ZAP: report failure to create directory
System.out.println("Failed to create directory " + f.getAbsolutePath());
}
}
f = new File(DIRBUSTER_CUSTOM_DIR);
if (!f.isDirectory()) {
LOGGER.info("Creating directory {}", DIRBUSTER_CUSTOM_DIR);
if (!f.mkdir()) {
// ZAP: report failure to create directory
System.out.println("Failed to create directory " + f.getAbsolutePath());
}
}
f = new File(FUZZER_DIR);
if (!f.isDirectory()) {
LOGGER.info("Creating directory {}", FUZZER_DIR);
if (!f.mkdir()) {
// ZAP: report failure to create directory
System.out.println("Failed to create directory " + f.getAbsolutePath());
}
}
f = new File(FOLDER_LOCAL_PLUGIN);
if (!f.isDirectory()) {
LOGGER.info("Creating directory {}", FOLDER_LOCAL_PLUGIN);
if (!f.mkdir()) {
// ZAP: report failure to create directory
System.out.println("Failed to create directory " + f.getAbsolutePath());
}
}
} catch (Exception e) {
System.err.println("Unable to initialize home directory! " + e.getMessage());
e.printStackTrace(System.err);
System.exit(1);
}
// Upgrade actions
try {
try {
// ZAP: Changed to use ZapXmlConfiguration, to enforce the same character encoding
// when reading/writing configurations.
XMLConfiguration config = new ZapXmlConfiguration(FILE_CONFIG);
config.setAutoSave(false);
long ver = config.getLong(VERSION_ELEMENT);
if (ver == VERSION_TAG) {
// Nothing to do
} else if (isDevMode() || isDailyBuild()) {
// Nothing to do
} else {
// Backup the old one
LOGGER.info("Backing up config file to {}.bak", FILE_CONFIG);
f = new File(FILE_CONFIG);
try {
copier.copy(f, new File(FILE_CONFIG + ".bak"));
} catch (IOException e) {
String msg =
"Failed to backup config file "
+ FILE_CONFIG
+ " to "
+ FILE_CONFIG
+ ".bak "
+ e.getMessage();
System.err.println(msg);
LOGGER.error(msg, e);
}
if (ver == V_PAROS_TAG) {
upgradeFrom1_1_0(config);
upgradeFrom1_2_0(config);
}
if (ver <= V_1_0_0_TAG) {
// Nothing to do
}
if (ver <= V_1_1_0_TAG) {
upgradeFrom1_1_0(config);
}
if (ver <= V_1_2_0_TAG) {
upgradeFrom1_2_0(config);
}
if (ver <= V_1_2_1_TAG) {
// Nothing to do
}
if (ver <= V_1_3_0_TAG) {
// Nothing to do
}
if (ver <= V_1_3_1_TAG) {
// Nothing to do
}
if (ver <= V_1_4_1_TAG) {
upgradeFrom1_4_1(config);
}
if (ver <= V_2_0_0_TAG) {
upgradeFrom2_0_0(config);
}
if (ver <= V_2_1_0_TAG) {
// Nothing to do
}
if (ver <= V_2_2_0_TAG) {
upgradeFrom2_2_0(config);
}
if (ver <= V_2_2_2_TAG) {
upgradeFrom2_2_2(config);
}
if (ver <= V_2_3_1_TAG) {
upgradeFrom2_3_1(config);
}
if (ver <= V_2_4_3_TAG) {
upgradeFrom2_4_3(config);
}
if (ver <= V_2_5_0_TAG) {
upgradeFrom2_5_0(config);
}
if (ver <= V_2_7_0_TAG) {
upgradeFrom2_7_0(config);
}
if (ver <= V_2_8_0_TAG) {
upgradeFrom2_8_0(config);
}
if (ver <= V_2_9_0_TAG) {
upgradeFrom2_9_0(config);
}
if (ver <= V_2_11_1_TAG) {
upgradeFrom2_11_1(config);
}
if (ver <= V_2_12_0_TAG) {
upgradeFrom2_12(config);
}
if (ver <= V_2_14_0_TAG) {
upgradeFrom2_14_0(config);
}
// Execute always to pick installer choices.
updateCfuFromDefaultConfig(config);
LOGGER.info("Upgraded from {}", ver);
setLatestVersion(config);
}
} catch (ConfigurationException | ConversionException | NoSuchElementException e) {
handleMalformedConfigFile(e);
}
} catch (Exception e) {
System.err.println(
"Unable to upgrade config file " + FILE_CONFIG + " " + e.getMessage());
e.printStackTrace(System.err);
System.exit(1);
}
// ZAP: Init i18n
Locale locale = loadLocale(overrides);
Locale.setDefault(locale);
messages = new I18N(locale);
}
boolean acquireHomeLock() {
try {
Path lockFile = Paths.get(zapHome, ".homelock");
if (Files.notExists(lockFile)) {
Files.createFile(lockFile);
}
homeLockFileChannel = FileChannel.open(lockFile, StandardOpenOption.WRITE);
homeLock = homeLockFileChannel.tryLock();
if (homeLock == null) {
System.err.println(
"The home directory is already in use. Ensure no other ZAP instances are running with the same home directory: "
+ zapHome);
return false;
}
return true;
} catch (Exception e) {
System.err.println("Failed to acquire home directory lock.");
e.printStackTrace();
return false;
}
}
private void renameOldWindowsHome() {
if (!isWindows()) {
return;
}
String home = getUserHome() + FILE_SEPARATOR + "OWASP ZAP";
if (isDevMode() || isDailyBuild()) {
home += "_D";
}
Path oldHome = Paths.get(getAbsolutePath(home));
if (Files.notExists(oldHome)) {
return;
}
Path newHome = Paths.get(getAbsolutePath(getDefaultHomeDirectory(true)));
if (Files.exists(newHome)) {
logAndPrintInfo("Not renaming old ZAP home, the new home already exists.");
return;
}
try {
Files.move(oldHome, newHome, StandardCopyOption.ATOMIC_MOVE);
logAndPrintInfo("Old ZAP home renamed to: " + newHome);
Path configFile = newHome.resolve(FILE_CONFIG_NAME);
if (Files.exists(configFile)) {
updatePathsInConfig(oldHome, newHome, new ZapXmlConfiguration(configFile.toFile()));
}
} catch (IOException e) {
logAndPrintError("Failed to rename the old home, will use a new home instead.", e);
} catch (ConfigurationException e) {
logAndPrintError("Failed to update home paths in configuration file:", e);
}
}
private static void updatePathsInConfig(Path oldHome, Path newHome, ZapXmlConfiguration config)
throws ConfigurationException {
config.getKeys()
.forEachRemaining(
key -> {
Path path = getPath(config.getString(key));
if (path == null || !path.startsWith(oldHome)) {
return;
}
Path newPath = newHome.resolve(oldHome.relativize(path));
config.setProperty(key, newPath.toString());
});
config.save();
}
private static Path getPath(String value) {
if (value == null || value.isBlank()) {
return null;
}
try {
return Paths.get(value);
} catch (Exception ignore) {
// Nothing to do.
}
return null;
}
private Locale loadLocale(ControlOverrides overrides) {
try {
String lang = null;
if (overrides != null) {
lang = overrides.getOrderedConfigs().get(OptionsParamView.LOCALE);
}
if (lang == null || lang.isEmpty()) {
XMLConfiguration config = new ZapXmlConfiguration(FILE_CONFIG);
config.setAutoSave(false);
lang = config.getString(OptionsParamView.LOCALE, OptionsParamView.DEFAULT_LOCALE);
if (lang.length() == 0) {
lang = OptionsParamView.DEFAULT_LOCALE;
}
}
String[] langArray = lang.split("_");
return new Locale.Builder().setLanguage(langArray[0]).setRegion(langArray[1]).build();
} catch (Exception e) {
System.out.println("Failed to load locale " + e);
}
return Locale.ENGLISH;
}
private void setUpLogging() throws IOException {
backupLegacyLog4jConfig();
String fileName = "log4j2.properties";
File logFile = new File(zapHome, fileName);
if (!logFile.exists()) {
String defaultConfig = "/org/zaproxy/zap/resources/log4j2-home.properties";
copyFileToHome(logFile.toPath(), "xml/" + fileName, defaultConfig);
}
Configurator.reconfigure(logFile.toURI());
}
private static void backupLegacyLog4jConfig() {
String fileName = "log4j.properties";
Path backupLegacyConfig = Paths.get(zapHome, fileName + ".bak");
if (Files.exists(backupLegacyConfig)) {
logAndPrintInfo("Ignoring legacy log4j.properties file, backup already exists.");
return;
}
Path legacyConfig = Paths.get(zapHome, fileName);
if (Files.exists(legacyConfig)) {
logAndPrintInfo("Creating backup of legacy log4j.properties file...");
try {
Files.move(legacyConfig, backupLegacyConfig);
} catch (IOException e) {
logAndPrintError("Failed to backup legacy Log4j configuration file:", e);
}
}
}
private void handleMalformedConfigFile(Exception e) throws IOException {
logAndPrintError("Failed to load/upgrade config file:", e);
try {
Path backupPath = Paths.get(zapHome, "config-" + Math.random() + ".xml.bak");
logAndPrintInfo("Creating back up for user inspection: " + backupPath);
Files.copy(Paths.get(FILE_CONFIG), backupPath);
logAndPrintInfo("Back up successfully created.");
} catch (IOException ioe) {
logAndPrintError("Failed to backup file:", ioe);
}
logAndPrintInfo("Using default config file...");
copyDefaultConfigFile();
}
private static void logAndPrintError(String message, Exception e) {
LOGGER.error(message, e);
System.err.println(message);
e.printStackTrace();
}
private static void logAndPrintInfo(String message) {
LOGGER.info(message);
System.out.println(message);
}
private void copyProperty(XMLConfiguration fromConfig, XMLConfiguration toConfig, String key) {
toConfig.setProperty(key, fromConfig.getProperty(key));
}
private void copyAllProperties(
XMLConfiguration fromConfig, XMLConfiguration toConfig, String prefix) {
Iterator iter = fromConfig.getKeys(prefix);
while (iter.hasNext()) {
String key = iter.next();
copyProperty(fromConfig, toConfig, key);
}
}
private void upgradeFrom1_1_0(XMLConfiguration config) throws ConfigurationException {
// Upgrade the regexs
// ZAP: Changed to use ZapXmlConfiguration, to enforce the same character encoding when
// reading/writing configurations.
XMLConfiguration newConfig = new ZapXmlConfiguration(getUrlDefaultConfigFile());
newConfig.setAutoSave(false);
copyAllProperties(newConfig, config, "pscans");
}
private void upgradeFrom1_2_0(XMLConfiguration config) throws ConfigurationException {
// Upgrade the regexs
// ZAP: Changed to use ZapXmlConfiguration, to enforce the same character encoding when
// reading/writing configurations.
XMLConfiguration newConfig = new ZapXmlConfiguration(getUrlDefaultConfigFile());
newConfig.setAutoSave(false);
copyProperty(newConfig, config, "view.brkPanelView");
copyProperty(newConfig, config, "view.showMainToolbar");
}
private void upgradeFrom1_4_1(XMLConfiguration config) {
// As the POST_FORM option for the spider has been updated from int to boolean, keep
// compatibility for old versions
Object postForm = config.getProperty("spider.postform");
if (postForm != null) {
boolean enabled = !"0".equals(postForm.toString());
config.setProperty("spider.postform", enabled);
config.setProperty("spider.processform", enabled);
}
// Move the old session tokens to the new "httpsessions" hierarchy and
// delete the old "session" hierarchy as it's no longer used/needed.
String[] tokens = config.getStringArray("session.tokens");
for (int i = 0; i < tokens.length; ++i) {
String elementBaseKey = "httpsessions.tokens.token(" + i + ").";
config.setProperty(elementBaseKey + "name", tokens[i]);
config.setProperty(elementBaseKey + "enabled", Boolean.TRUE);
}
config.clearTree("session");
// Update the anti CSRF tokens elements/hierarchy.
tokens = config.getStringArray("anticsrf.tokens");
config.clearTree("anticsrf.tokens");
for (int i = 0; i < tokens.length; ++i) {
String elementBaseKey = "anticsrf.tokens.token(" + i + ").";
config.setProperty(elementBaseKey + "name", tokens[i]);
config.setProperty(elementBaseKey + "enabled", Boolean.TRUE);
}
// Update the invoke applications elements/hierarchy.
List