View Javadoc
1   /*
2    * This file is part of dependency-check-ant.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   *
16   * Copyright (c) 2015 Jeremy Long. All Rights Reserved.
17   */
18  package org.owasp.dependencycheck.taskdefs;
19  
20  import io.github.jeremylong.jcs3.slf4j.Slf4jAdapter;
21  import java.io.File;
22  import java.io.IOException;
23  import java.io.InputStream;
24  
25  import org.apache.tools.ant.BuildException;
26  import org.apache.tools.ant.Project;
27  import org.apache.tools.ant.Task;
28  import org.owasp.dependencycheck.Engine;
29  import org.owasp.dependencycheck.utils.Downloader;
30  import org.owasp.dependencycheck.utils.InvalidSettingException;
31  import org.owasp.dependencycheck.utils.Settings;
32  import org.slf4j.impl.StaticLoggerBinder;
33  
34  /**
35   * An Ant task definition to execute dependency-check during an Ant build.
36   *
37   * @author Jeremy Long
38   */
39  public class Purge extends Task {
40  
41      /**
42       * The properties file location.
43       */
44      private static final String PROPERTIES_FILE = "task.properties";
45      /**
46       * The configured settings.
47       */
48      private Settings settings;
49  
50      /**
51       * The location of the data directory that contains
52       */
53      private String dataDirectory = null;
54      /**
55       * Indicates if dependency-check should fail the build if an exception
56       * occurs.
57       */
58      private boolean failOnError = true;
59  
60      /**
61       * Construct a new DependencyCheckTask.
62       */
63      public Purge() {
64          super();
65  
66          // Call this before Dependency Check Core starts logging anything - this way, all SLF4J messages from
67          // core end up coming through this tasks logger
68          StaticLoggerBinder.getSingleton().setTask(this);
69      }
70  
71      public Settings getSettings() {
72          return settings;
73      }
74  
75      /**
76       * Set the value of dataDirectory.
77       *
78       * @param dataDirectory new value of dataDirectory
79       */
80      public void setDataDirectory(String dataDirectory) {
81          this.dataDirectory = dataDirectory;
82      }
83  
84      /**
85       * Get the value of failOnError.
86       *
87       * @return the value of failOnError
88       */
89      public boolean isFailOnError() {
90          return failOnError;
91      }
92  
93      /**
94       * Set the value of failOnError.
95       *
96       * @param failOnError new value of failOnError
97       */
98      public void setFailOnError(boolean failOnError) {
99          this.failOnError = failOnError;
100     }
101 
102     /**
103      * Sets the
104      * {@link Thread#getContextClassLoader() Thread Context Class Loader} to the
105      * one for this class, and then calls
106      * {@link #executeWithContextClassloader()}. This is done because the JCS
107      * cache needs to have the Thread Context Class Loader set to something that
108      * can resolve it's classes. Other build tools do this by default but Ant
109      * does not.
110      *
111      * @throws BuildException throws if there is a problem. See
112      * {@link #executeWithContextClassloader()} for details
113      */
114     @Override
115     public final void execute() throws BuildException {
116         muteNoisyLoggers();
117         final ClassLoader current = Thread.currentThread().getContextClassLoader();
118         try {
119             Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
120 
121             executeWithContextClassloader();
122         } finally {
123             Thread.currentThread().setContextClassLoader(current);
124         }
125     }
126 
127     /**
128      * Hacky method of muting the noisy logging from JCS.
129      */
130     private void muteNoisyLoggers() {
131         System.setProperty("jcs.logSystem", "slf4j");
132         Slf4jAdapter.muteLogging(true);
133 
134         final String[] noisyLoggers = {
135             "org.apache.hc"
136         };
137         for (String loggerName : noisyLoggers) {
138             System.setProperty("org.slf4j.simpleLogger.log." + loggerName, "error");
139         }
140     }
141 
142     /**
143      * Executes the dependency-check purge to delete the existing local copy of
144      * the NVD CVE data.
145      *
146      * @throws BuildException thrown if there is a problem deleting the file(s)
147      */
148     //see note on `Check.dealWithReferences()` for information on this suppression
149     @SuppressWarnings("squid:RedundantThrowsDeclarationCheck")
150     protected void executeWithContextClassloader() throws BuildException {
151         populateSettings();
152         try {
153             Downloader.getInstance().configure(settings);
154         } catch (InvalidSettingException e) {
155             throw new BuildException(e);
156         }
157         try (Engine engine = new Engine(Engine.Mode.EVIDENCE_PROCESSING, getSettings())) {
158             engine.purge();
159         } finally {
160             settings.cleanup(true);
161         }
162     }
163 
164     /**
165      * Takes the properties supplied and updates the dependency-check settings.
166      * Additionally, this sets the system properties required to change the
167      * proxy server, port, and connection timeout.
168      *
169      * @throws BuildException thrown if the properties file cannot be read.
170      */
171     //see note on `Check.dealWithReferences()` for information on this suppression
172     @SuppressWarnings("squid:RedundantThrowsDeclarationCheck")
173     protected void populateSettings() throws BuildException {
174         settings = new Settings();
175         try (InputStream taskProperties = this.getClass().getClassLoader().getResourceAsStream(PROPERTIES_FILE)) {
176             settings.mergeProperties(taskProperties);
177         } catch (IOException ex) {
178             final String msg = "Unable to load the dependency-check ant task.properties file.";
179             if (this.failOnError) {
180                 throw new BuildException(msg, ex);
181             }
182             log(msg, ex, Project.MSG_WARN);
183         }
184         if (dataDirectory != null) {
185             settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDirectory);
186         } else {
187             final File jarPath = new File(Purge.class.getProtectionDomain().getCodeSource().getLocation().getPath());
188             final File base = jarPath.getParentFile();
189             final String sub = settings.getString(Settings.KEYS.DATA_DIRECTORY);
190             final File dataDir = new File(base, sub);
191             settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDir.getAbsolutePath());
192         }
193     }
194 }