/*
* Zed Attack Proxy (ZAP) and its related class files.
*
* ZAP is an HTTP/HTTPS proxy for assessing web application security.
*
* Copyright 2010 psiinon@gmail.com
*
* 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.autoupdate;
import java.io.File;
import java.security.InvalidParameterException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.ConversionException;
import org.apache.log4j.Logger;
import org.parosproxy.paros.Constant;
import org.parosproxy.paros.common.AbstractParam;
import org.zaproxy.zap.extension.api.ZapApiIgnore;
public class OptionsParamCheckForUpdates extends AbstractParam {
public static final String CHECK_ON_START = "start.checkForUpdates";
public static final String DAY_LAST_CHECKED = "start.dayLastChecked";
public static final String DAY_LAST_INSTALL_WARNED = "start.dayLastInstallWarned";
public static final String DAY_LAST_UPDATE_WARNED = "start.dayLastUpdateWarned";
public static final String DOWNLOAD_NEW_RELEASE = "start.downloadNewRelease";
public static final String CHECK_ADDON_UPDATES = "start.checkAddonUpdates";
public static final String INSTALL_ADDON_UPDATES = "start.installAddonUpdates";
public static final String INSTALL_SCANNER_RULES = "start.installScannerRules";
public static final String REPORT_RELEASE_ADDON = "start.reportReleaseAddons";
public static final String REPORT_BETA_ADDON = "start.reportBetaAddons";
public static final String REPORT_ALPHA_ADDON = "start.reportAlphaAddons";
public static final String ADDON_DIRS = "start.addonDirs";
public static final String DOWNLOAD_DIR = "start.downloadDir";
private static String SDF_FORMAT = "yyyy-MM-dd";
private boolean checkOnStart;
private boolean downloadNewRelease = false;
private boolean checkAddonUpdates = false;
private boolean installAddonUpdates = false;
private boolean installScannerRules = false;
private boolean reportReleaseAddons = false;
private boolean reportBetaAddons = false;
private boolean reportAlphaAddons = false;
private List<File> addonDirectories = new ArrayList<File>();
private File downloadDirectory = new File(Constant.FOLDER_LOCAL_PLUGIN);
// Day last checked is used to ensure if the user has agreed then we only check the first time ZAP is run every day
private String dayLastChecked = null;
private String dayLastInstallWarned = null;
private String dayLastUpdateWarned = null;
private boolean unset = true;
private static Logger log = Logger.getLogger(OptionsParamCheckForUpdates.class);
public OptionsParamCheckForUpdates() {
}
@Override
protected void parse() {
updateOldOptions();
checkOnStart = getConfig().getBoolean(CHECK_ON_START, false);
dayLastChecked = getConfig().getString(DAY_LAST_CHECKED, "");
// There was a bug in 1.2.0 where it defaulted silently to dont check
// We now use the lack of a dayLastChecked value to indicate we should reprompt the user.
unset = dayLastChecked.length() == 0;
dayLastInstallWarned = getConfig().getString(DAY_LAST_INSTALL_WARNED, "");
dayLastUpdateWarned = getConfig().getString(DAY_LAST_UPDATE_WARNED, "");
downloadNewRelease = getConfig().getBoolean(DOWNLOAD_NEW_RELEASE, false);
checkAddonUpdates = getConfig().getBoolean(CHECK_ADDON_UPDATES, false);
installAddonUpdates = getConfig().getBoolean(INSTALL_ADDON_UPDATES, false);
installScannerRules = getConfig().getBoolean(INSTALL_SCANNER_RULES, false);
reportReleaseAddons = getConfig().getBoolean(REPORT_RELEASE_ADDON, false);
reportBetaAddons = getConfig().getBoolean(REPORT_BETA_ADDON, false);
reportAlphaAddons = getConfig().getBoolean(REPORT_ALPHA_ADDON, false);
for (Object dir : getConfig().getList(ADDON_DIRS)) {
File f = new File(dir.toString());
if (!f.exists()) {
log.error("Add-on directory does not exist: " + f.getAbsolutePath());
} else if (! f.isDirectory()) {
log.error("Add-on directory is not a directory: " + f.getAbsolutePath());
} else if (! f.canRead()) {
log.error("Add-on directory not readable: " + f.getAbsolutePath());
} else {
this.addonDirectories.add(f);
}
}
setDownloadDirectory(new File(getConfig().getString(DOWNLOAD_DIR, Constant.FOLDER_LOCAL_PLUGIN)), false);
}
private void updateOldOptions() {
try {
int oldValue = getConfig().getInt(CHECK_ON_START, 0);
getConfig().setProperty(CHECK_ON_START, Boolean.valueOf(oldValue != 0));
} catch(ConversionException ignore) {
// Option already using boolean type.
}
}
@ZapApiIgnore
public boolean isCheckOnStartUnset() {
return unset;
}
/**
* @param checkOnStart 0 to disable check for updates on startup, any other number to enable.
* @deprecated (2.3.0) Replaced by {@link #setCheckOnStart(boolean)}. It will be removed in a future release.
*/
@Deprecated
@ZapApiIgnore
public void setCheckOnStart(int checkOnStart) {
setCheckOnStart(checkOnStart != 0);
}
/**
* Sets whether or not the "check for updates on start up" is enabled.
*
* @param checkOnStart {@code true} if the "check for updates on start up" should be enabled, {@code false} otherwise.
*/
public void setCheckOnStart(boolean checkOnStart) {
this.checkOnStart = checkOnStart;
getConfig().setProperty(CHECK_ON_START, Boolean.valueOf(checkOnStart));
if (dayLastChecked.length() == 0) {
dayLastChecked = "Never";
getConfig().setProperty(DAY_LAST_CHECKED, dayLastChecked);
}
}
/**
* Tells whether or not the option "check for updates on start up" is enabled.
*
* @return {@code true} if check for updates on start up is enabled, {@code false} otherwise.
* @see #checkOnStart()
*/
public boolean isCheckOnStart() {
return checkOnStart;
}
/**
* Get a new SimpleDateFormat each time for thread safeness
* @return
*/
private SimpleDateFormat getSdf() {
return new SimpleDateFormat(SDF_FORMAT);
}
/**
* Tells whether or not a "check for updates on start up" needs to be performed.
* <p>
* A check for updates needs to be performed if the method {@code isCheckOnStart()} returns {@code true} and if no check was
* already done during the same day.
* </p>
*
* @return {@code true} if a check for updates on start up needs to be performed, {@code false} otherwise.
* @see #isCheckOnStart()
*/
@ZapApiIgnore
public boolean checkOnStart() {
if (!checkOnStart) {
log.debug("isCheckForStart - false");
return false;
}
String today = getSdf().format(new Date());
if (today.equals(dayLastChecked)) {
log.debug("isCheckForStart - already checked today");
return false;
}
getConfig().setProperty(DAY_LAST_CHECKED, today);
try {
getConfig().save();
} catch (ConfigurationException e) {
log.error(e.getMessage(), e);
}
return true;
}
/**
* Returns the date the last check for updates check was made, or null if no check has been made
* @return
*/
public Date getDayLastChecked() {
try {
return getSdf().parse(dayLastChecked);
} catch (ParseException e) {
// Assume its not been checked
return null;
}
}
/**
* Returns the date the last check for warning about out of date ZAP / add-ons was made,
* or null if no check has been made
* @return
*/
public Date getDayLastInstallWarned() {
try {
return getSdf().parse(dayLastInstallWarned);
} catch (ParseException e) {
// Assume we've never warned
return null;
}
}
/**
* Returns the date the last check for warning about out of date add-ons was made,
* or null if no check has been made
* @return
*/
public Date getDayLastUpdateWarned() {
try {
return getSdf().parse(dayLastUpdateWarned);
} catch (ParseException e) {
// Assume we've never warned
return null;
}
}
public void setDayLastInstallWarned() {
getConfig().setProperty(DAY_LAST_INSTALL_WARNED, getSdf().format(new Date()));
try {
getConfig().save();
} catch (ConfigurationException e) {
log.error(e.getMessage(), e);
}
}
public void setDayLastUpdateWarned() {
getConfig().setProperty(DAY_LAST_UPDATE_WARNED, getSdf().format(new Date()));
try {
getConfig().save();
} catch (ConfigurationException e) {
log.error(e.getMessage(), e);
}
}
public boolean isDownloadNewRelease() {
return downloadNewRelease;
}
public void setDownloadNewRelease(boolean downloadNewRelease) {
this.downloadNewRelease = downloadNewRelease;
getConfig().setProperty(DOWNLOAD_NEW_RELEASE, this.downloadNewRelease);
}
public boolean isCheckAddonUpdates() {
return checkAddonUpdates;
}
public void setCheckAddonUpdates(boolean checkAddonUpdates) {
this.checkAddonUpdates = checkAddonUpdates;
getConfig().setProperty(CHECK_ADDON_UPDATES, checkAddonUpdates);
}
public boolean isInstallAddonUpdates() {
return installAddonUpdates;
}
public void setInstallAddonUpdates(boolean installAddonUpdates) {
this.installAddonUpdates = installAddonUpdates;
getConfig().setProperty(INSTALL_ADDON_UPDATES, installAddonUpdates);
}
public boolean isInstallScannerRules() {
return installScannerRules;
}
public void setInstallScannerRules(boolean installScannerRules) {
this.installScannerRules = installScannerRules;
getConfig().setProperty(INSTALL_SCANNER_RULES, installScannerRules);
}
public boolean isReportReleaseAddons() {
return reportReleaseAddons;
}
public void setReportReleaseAddons(boolean reportReleaseAddons) {
this.reportReleaseAddons = reportReleaseAddons;
getConfig().setProperty(REPORT_RELEASE_ADDON, reportReleaseAddons);
}
public boolean isReportBetaAddons() {
return reportBetaAddons;
}
public void setReportBetaAddons(boolean reportBetaAddons) {
this.reportBetaAddons = reportBetaAddons;
getConfig().setProperty(REPORT_BETA_ADDON, reportBetaAddons);
}
public boolean isReportAlphaAddons() {
return reportAlphaAddons;
}
public void setReportAlphaAddons(boolean reportAlphaAddons) {
this.reportAlphaAddons = reportAlphaAddons;
getConfig().setProperty(REPORT_ALPHA_ADDON, reportAlphaAddons);
}
public List<File> getAddonDirectories() {
return addonDirectories;
}
public void setAddonDirectories(List<File> addonDirectories) {
this.addonDirectories = addonDirectories;
getConfig().setProperty(ADDON_DIRS, addonDirectories);
}
public File getDownloadDirectory() {
return downloadDirectory;
}
public void setDownloadDirectory(File downloadDirectory) throws InvalidParameterException {
setDownloadDirectory(downloadDirectory, true);
}
private void setDownloadDirectory(File downloadDirectory, boolean save) throws InvalidParameterException {
if (!Constant.FOLDER_LOCAL_PLUGIN.equals(downloadDirectory.getAbsolutePath())) {
// Check its one of the extra addon dirs
boolean found = false;
for (File f : this.addonDirectories) {
if (f.equals(downloadDirectory)) {
found = true;
break;
}
}
if (!found) {
throw new InvalidParameterException(
"Directory must be the default one or one of the addonDirectories " +
downloadDirectory.getAbsolutePath());
}
}
if (!downloadDirectory.canWrite()) {
throw new InvalidParameterException(
"No write access to directory " +
downloadDirectory.getAbsolutePath());
}
this.downloadDirectory = downloadDirectory;
if (save) {
getConfig().setProperty(DOWNLOAD_DIR, downloadDirectory.getAbsolutePath());
}
}
}