Update.java

/*
 * This file is part of dependency-check-ant.
 *
 * 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.
 *
 * Copyright (c) 2015 Jeremy Long. All Rights Reserved.
 */
package org.owasp.dependencycheck.taskdefs;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.data.update.exception.UpdateException;
import org.owasp.dependencycheck.utils.Downloader;
import org.owasp.dependencycheck.utils.InvalidSettingException;
import org.owasp.dependencycheck.utils.Settings;
import org.slf4j.impl.StaticLoggerBinder;

/**
 * An Ant task definition to execute dependency-check update. This will download
 * the latest data from the National Vulnerability Database (NVD) and store a
 * copy in the local database.
 *
 * @author Jeremy Long
 */
//While duplicate code is general bad - this is calling out getters/setters
//on unrelated ODC clients (the DependencyCheckScanAgent).
@SuppressWarnings("common-java:DuplicatedBlocks")
public class Update extends Purge {

    /**
     * The NVD API endpoint.
     */
    private String nvdApiEndpoint;
    /**
     * The NVD API Key.
     */
    private String nvdApiKey;
    /**
     * The maximum number of retry requests for a single call to the NVD API.
     */
    private Integer nvdMaxRetryCount;
    /**
     * The number of hours to wait before checking for new updates from the NVD.
     */
    private Integer nvdValidForHours;
    /**
     * The NVD API Data Feed URL.
     */
    private String nvdDatafeedUrl;
    /**
     * The username for basic auth to the NVD Data Feed.
     */
    private String nvdUser;
    /**
     * The password for basic auth to the NVD Data Feed.
     */
    private String nvdPassword;
    /**
     * The time in milliseconds to wait between downloading NVD API data.
     */
    private int nvdApiDelay = 0;

    /**
     * The number of records per page of NVD API data.
     */
    private Integer nvdApiResultsPerPage;

    /**
     * The Proxy Server.
     */
    private String proxyServer;
    /**
     * The Proxy Port.
     */
    private String proxyPort;
    /**
     * The Proxy username.
     */
    private String proxyUsername;
    /**
     * The Proxy password.
     */
    private String proxyPassword;
    /**
     * Non proxy hosts
     */
    private String nonProxyHosts;
    /**
     * The Connection Timeout.
     */
    private String connectionTimeout;
    /**
     * The Read Timeout.
     */
    private String readTimeout;
    /**
     * The database driver name; such as org.h2.Driver.
     */
    private String databaseDriverName;
    /**
     * The path to the database driver JAR file if it is not on the class path.
     */
    private String databaseDriverPath;
    /**
     * The database connection string.
     */
    private String connectionString;
    /**
     * The user name for connecting to the database.
     */
    private String databaseUser;
    /**
     * The password to use when connecting to the database.
     */
    private String databasePassword;
    /**
     * The number of hours to wait before re-checking hosted suppressions file
     * for updates.
     */
    private Integer hostedSuppressionsValidForHours;
    /**
     * Whether the hosted suppressions file will be updated regardless of the
     * `autoupdate` settings. Defaults to false.
     */
    private Boolean hostedSuppressionsForceUpdate;
    /**
     * Whether the hosted suppressions file will be used. Defaults to true.
     */
    private Boolean hostedSuppressionsEnabled;

    /**
     * Construct a new UpdateTask.
     */
    public Update() {
        super();
        // Call this before Dependency Check Core starts logging anything - this way, all SLF4J messages from
        // core end up coming through this tasks logger
        StaticLoggerBinder.getSingleton().setTask(this);
    }

    /**
     * Get the value of nvdApiEndpoint.
     *
     * @return the value of nvdApiEndpoint
     */
    public String getNvdApiEndpoint() {
        return nvdApiEndpoint;
    }

    /**
     * Set the value of nvdApiEndpoint.
     *
     * @param nvdApiEndpoint new value of nvdApiEndpoint
     */
    public void setNvdApiEndpoint(String nvdApiEndpoint) {
        this.nvdApiEndpoint = nvdApiEndpoint;
    }

    /**
     * Get the value of nvdApiKey.
     *
     * @return the value of nvdApiKey
     */
    public String getNvdApiKey() {
        return nvdApiKey;
    }

    /**
     * Set the value of nvdApiKey.
     *
     * @param nvdApiKey new value of nvdApiKey
     */
    public void setNvdApiKey(String nvdApiKey) {
        this.nvdApiKey = nvdApiKey;
    }

    /**
     * Get the value of nvdMaxRetryCount.
     *
     * @return the value of nvdMaxRetryCount
     */
    public int getNvdMaxRetryCounts() {
        return nvdMaxRetryCount;
    }

    /**
     * Set the value of nvdMaxRetryCount.
     *
     * @param nvdMaxRetryCount new value of nvdMaxRetryCount
     */
    public void setNvdMaxRetryCount(int nvdMaxRetryCount) {
        this.nvdMaxRetryCount = nvdMaxRetryCount;
    }

    /**
     * Get the value of nvdValidForHours.
     *
     * @return the value of nvdValidForHours
     */
    public int getNvdValidForHours() {
        return nvdValidForHours;
    }

    /**
     * Set the value of nvdValidForHours.
     *
     * @param nvdValidForHours new value of nvdValidForHours
     */
    public void setNvdValidForHours(int nvdValidForHours) {
        this.nvdValidForHours = nvdValidForHours;
    }

    /**
     * Get the value of nvdDatafeedUrl.
     *
     * @return the value of nvdDatafeedUrl
     */
    public String getNvdDatafeedUrl() {
        return nvdDatafeedUrl;
    }

    /**
     * Set the value of nvdDatafeedUrl.
     *
     * @param nvdDatafeedUrl new value of nvdDatafeedUrl
     */
    public void setNvdDatafeedUrl(String nvdDatafeedUrl) {
        this.nvdDatafeedUrl = nvdDatafeedUrl;
    }

    /**
     * Get the value of nvdUser.
     *
     * @return the value of nvdUser
     */
    public String getNvdUser() {
        return nvdUser;
    }

    /**
     * Set the value of nvdUser.
     *
     * @param nvdUser new value of nvdUser
     */
    public void setNvdUser(String nvdUser) {
        this.nvdUser = nvdUser;
    }

    /**
     * Get the value of nvdPassword.
     *
     * @return the value of nvdPassword
     */
    public String getNvdPassword() {
        return nvdPassword;
    }

    /**
     * Set the value of nvdPassword.
     *
     * @param nvdPassword new value of nvdPassword
     */
    public void setNvdPassword(String nvdPassword) {
        this.nvdPassword = nvdPassword;
    }

    /**
     * Get the value of nvdApiDelay.
     *
     * @return the value of nvdApiDelay
     */
    public int getNvdApiDelay() {
        return nvdApiDelay;
    }

    /**
     * Set the value of nvdApiDelay.
     *
     * @param nvdApiDelay new value of nvdApiDelay
     */
    public void setNvdApiDelay(int nvdApiDelay) {
        this.nvdApiDelay = nvdApiDelay;
    }

    /**
     * Get the value of nvdApiResultsPerPage.
     *
     * @return the value of nvdApiResultsPerPage
     */
    public int getNvdApiResultsPerPage() {
        return nvdApiResultsPerPage;
    }

    /**
     * Set the value of nvdApiResultsPerPage.
     *
     * @param nvdApiResultsPerPage new value of nvdApiResultsPerPage
     */
    public void setApiResultsPerPage(int nvdApiResultsPerPage) {
        this.nvdApiResultsPerPage = nvdApiResultsPerPage;
    }

    /**
     * Get the value of proxyServer.
     *
     * @return the value of proxyServer
     */
    public String getProxyServer() {
        return proxyServer;
    }

    /**
     * Set the value of proxyServer.
     *
     * @param server new value of proxyServer
     */
    public void setProxyServer(String server) {
        this.proxyServer = server;
    }

    /**
     * Get the value of proxyPort.
     *
     * @return the value of proxyPort
     */
    public String getProxyPort() {
        return proxyPort;
    }

    /**
     * Set the value of proxyPort.
     *
     * @param proxyPort new value of proxyPort
     */
    public void setProxyPort(String proxyPort) {
        this.proxyPort = proxyPort;
    }

    /**
     * Get the value of proxyUsername.
     *
     * @return the value of proxyUsername
     */
    public String getProxyUsername() {
        return proxyUsername;
    }

    /**
     * Set the value of proxyUsername.
     *
     * @param proxyUsername new value of proxyUsername
     */
    public void setProxyUsername(String proxyUsername) {
        this.proxyUsername = proxyUsername;
    }

    /**
     * Get the value of proxyPassword.
     *
     * @return the value of proxyPassword
     */
    public String getProxyPassword() {
        return proxyPassword;
    }

    /**
     * Set the value of proxyPassword.
     *
     * @param proxyPassword new value of proxyPassword
     */
    public void setProxyPassword(String proxyPassword) {
        this.proxyPassword = proxyPassword;
    }

    /**
     * Get the value of nonProxyHosts.
     *
     * @return the value of nonProxyHosts
     */
    public String getNonProxyHosts() {
        return nonProxyHosts;
    }

    /**
     * Set the value of nonProxyHosts.
     *
     * @param nonProxyHosts new value of nonProxyHosts
     */
    public void setNonProxyHosts(String nonProxyHosts) {
        this.nonProxyHosts = nonProxyHosts;
    }

    /**
     * Get the value of connectionTimeout.
     *
     * @return the value of connectionTimeout
     */
    public String getConnectionTimeout() {
        return connectionTimeout;
    }

    /**
     * Set the value of connectionTimeout.
     *
     * @param connectionTimeout new value of connectionTimeout
     */
    public void setConnectionTimeout(String connectionTimeout) {
        this.connectionTimeout = connectionTimeout;
    }

    /**
     * Get the value of readTimeout.
     *
     * @return the value of readTimeout
     */
    public String getReadTimeout() {
        return readTimeout;
    }

    /**
     * Set the value of readTimeout.
     *
     * @param readTimeout new value of readTimeout
     */
    public void setReadTimeout(String readTimeout) {
        this.readTimeout = readTimeout;
    }

    /**
     * Get the value of databaseDriverName.
     *
     * @return the value of databaseDriverName
     */
    public String getDatabaseDriverName() {
        return databaseDriverName;
    }

    /**
     * Set the value of databaseDriverName.
     *
     * @param databaseDriverName new value of databaseDriverName
     */
    public void setDatabaseDriverName(String databaseDriverName) {
        this.databaseDriverName = databaseDriverName;
    }

    /**
     * Get the value of databaseDriverPath.
     *
     * @return the value of databaseDriverPath
     */
    public String getDatabaseDriverPath() {
        return databaseDriverPath;
    }

    /**
     * Set the value of databaseDriverPath.
     *
     * @param databaseDriverPath new value of databaseDriverPath
     */
    public void setDatabaseDriverPath(String databaseDriverPath) {
        this.databaseDriverPath = databaseDriverPath;
    }

    /**
     * Get the value of connectionString.
     *
     * @return the value of connectionString
     */
    public String getConnectionString() {
        return connectionString;
    }

    /**
     * Set the value of connectionString.
     *
     * @param connectionString new value of connectionString
     */
    public void setConnectionString(String connectionString) {
        this.connectionString = connectionString;
    }

    /**
     * Get the value of databaseUser.
     *
     * @return the value of databaseUser
     */
    public String getDatabaseUser() {
        return databaseUser;
    }

    /**
     * Set the value of databaseUser.
     *
     * @param databaseUser new value of databaseUser
     */
    public void setDatabaseUser(String databaseUser) {
        this.databaseUser = databaseUser;
    }

    /**
     * Get the value of databasePassword.
     *
     * @return the value of databasePassword
     */
    public String getDatabasePassword() {
        return databasePassword;
    }

    /**
     * Set the value of databasePassword.
     *
     * @param databasePassword new value of databasePassword
     */
    public void setDatabasePassword(String databasePassword) {
        this.databasePassword = databasePassword;
    }

    /**
     * Get the value of hostedSuppressionsValidForHours.
     *
     * @return the value of hostedSuppressionsValidForHours
     */
    public Integer getHostedSuppressionsValidForHours() {
        return hostedSuppressionsValidForHours;
    }

    /**
     * Set the value of hostedSuppressionsValidForHours.
     *
     * @param hostedSuppressionsValidForHours new value of
     * hostedSuppressionsValidForHours
     */
    public void setHostedSuppressionsValidForHours(final Integer hostedSuppressionsValidForHours) {
        this.hostedSuppressionsValidForHours = hostedSuppressionsValidForHours;
    }

    /**
     * Get the value of hostedSuppressionsForceUpdate.
     *
     * @return the value of hostedSuppressionsForceUpdate
     */
    public Boolean isHostedSuppressionsForceUpdate() {
        return hostedSuppressionsForceUpdate;
    }

    /**
     * Set the value of hostedSuppressionsForceUpdate.
     *
     * @param hostedSuppressionsForceUpdate new value of
     * hostedSuppressionsForceUpdate
     */
    public void setHostedSuppressionsForceUpdate(final Boolean hostedSuppressionsForceUpdate) {
        this.hostedSuppressionsForceUpdate = hostedSuppressionsForceUpdate;
    }

    /**
     * Get the value of hostedSuppressionsEnabled.
     *
     * @return the value of hostedSuppressionsEnabled
     */
    public Boolean isHostedSuppressionsEnabled() {
        return hostedSuppressionsEnabled;
    }

    /**
     * Set the value of hostedSuppressionsEnabled.
     *
     * @param hostedSuppressionsEnabled new value of hostedSuppressionsEnabled
     */
    public void setHostedSuppressionsEnabled(Boolean hostedSuppressionsEnabled) {
        this.hostedSuppressionsEnabled = hostedSuppressionsEnabled;
    }

    /**
     * Executes the update by initializing the settings, downloads the NVD XML
     * data, and then processes the data storing it in the local database.
     *
     * @throws BuildException thrown if a connection to the local database
     * cannot be made.
     */
    //see note on `Check.dealWithReferences()` for information on this suppression
    @SuppressWarnings("squid:RedundantThrowsDeclarationCheck")
    @Override
    protected void executeWithContextClassloader() throws BuildException {
        populateSettings();
        try {
            Downloader.getInstance().configure(getSettings());
        } catch (InvalidSettingException e) {
            throw new BuildException(e);
        }
        try (Engine engine = new Engine(Update.class.getClassLoader(), getSettings())) {
            engine.doUpdates();
        } catch (UpdateException ex) {
            if (this.isFailOnError()) {
                throw new BuildException(ex);
            }
            log(ex.getMessage(), Project.MSG_ERR);
        } catch (DatabaseException ex) {
            final String msg = "Unable to connect to the dependency-check database; unable to update the NVD data";
            if (this.isFailOnError()) {
                throw new BuildException(msg, ex);
            }
            log(msg, Project.MSG_ERR);
        } finally {
            getSettings().cleanup();
        }
    }

    /**
     * Takes the properties supplied and updates the dependency-check settings.
     * Additionally, this sets the system properties required to change the
     * proxy server, port, and connection timeout.
     *
     * @throws BuildException thrown when an invalid setting is configured.
     */
    //see note on `Check.dealWithReferences()` for information on this suppression
    @SuppressWarnings("squid:RedundantThrowsDeclarationCheck")
    @Override
    protected void populateSettings() throws BuildException {
        super.populateSettings();
        getSettings().setStringIfNotEmpty(Settings.KEYS.PROXY_SERVER, proxyServer);
        getSettings().setStringIfNotEmpty(Settings.KEYS.PROXY_PORT, proxyPort);
        getSettings().setStringIfNotEmpty(Settings.KEYS.PROXY_USERNAME, proxyUsername);
        getSettings().setStringIfNotEmpty(Settings.KEYS.PROXY_PASSWORD, proxyPassword);
        getSettings().setStringIfNotEmpty(Settings.KEYS.PROXY_NON_PROXY_HOSTS, nonProxyHosts);
        getSettings().setStringIfNotEmpty(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
        getSettings().setStringIfNotEmpty(Settings.KEYS.CONNECTION_READ_TIMEOUT, readTimeout);
        getSettings().setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
        getSettings().setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath);
        getSettings().setStringIfNotEmpty(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
        getSettings().setStringIfNotEmpty(Settings.KEYS.DB_USER, databaseUser);
        getSettings().setStringIfNotEmpty(Settings.KEYS.DB_PASSWORD, databasePassword);
        getSettings().setIntIfNotNull(Settings.KEYS.HOSTED_SUPPRESSIONS_VALID_FOR_HOURS, hostedSuppressionsValidForHours);
        getSettings().setBooleanIfNotNull(Settings.KEYS.HOSTED_SUPPRESSIONS_FORCEUPDATE, hostedSuppressionsForceUpdate);
        getSettings().setBooleanIfNotNull(Settings.KEYS.HOSTED_SUPPRESSIONS_ENABLED, hostedSuppressionsEnabled);

        getSettings().setStringIfNotEmpty(Settings.KEYS.NVD_API_KEY, nvdApiKey);
        getSettings().setStringIfNotEmpty(Settings.KEYS.NVD_API_ENDPOINT, nvdApiEndpoint);
        getSettings().setIntIfNotNull(Settings.KEYS.NVD_API_DELAY, nvdApiDelay);
        getSettings().setIntIfNotNull(Settings.KEYS.NVD_API_RESULTS_PER_PAGE, nvdApiResultsPerPage);
        getSettings().setStringIfNotEmpty(Settings.KEYS.NVD_API_DATAFEED_URL, nvdDatafeedUrl);
        getSettings().setStringIfNotEmpty(Settings.KEYS.NVD_API_DATAFEED_USER, nvdUser);
        getSettings().setStringIfNotEmpty(Settings.KEYS.NVD_API_DATAFEED_PASSWORD, nvdPassword);
        if (nvdMaxRetryCount != null) {
            if (nvdMaxRetryCount > 0) {
                getSettings().setInt(Settings.KEYS.NVD_API_MAX_RETRY_COUNT, nvdMaxRetryCount);
            } else {
                throw new BuildException("Invalid setting: `nvdMaxRetryCount` must be greater than zero");
            }
        }
        if (nvdValidForHours != null) {
            if (nvdValidForHours >= 0) {
                getSettings().setInt(Settings.KEYS.NVD_API_VALID_FOR_HOURS, nvdValidForHours);
            } else {
                throw new BuildException("Invalid setting: `nvdValidForHours` must be 0 or greater");
            }
        }
    }
}