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       * The URL to hosted suppressions file with base FP suppressions.
62       */
63      private String hostedSuppressionsUrl = null;
64  
65      /**
66       * Construct a new DependencyCheckTask.
67       */
68      public Purge() {
69          super();
70  
71          // Call this before Dependency Check Core starts logging anything - this way, all SLF4J messages from
72          // core end up coming through this tasks logger
73          StaticLoggerBinder.getSingleton().setTask(this);
74      }
75  
76      public Settings getSettings() {
77          return settings;
78      }
79  
80      /**
81       * Get the value of dataDirectory.
82       *
83       * @return the value of dataDirectory
84       */
85      public String getDataDirectory() {
86          return dataDirectory;
87      }
88  
89      /**
90       * Set the value of dataDirectory.
91       *
92       * @param dataDirectory new value of dataDirectory
93       */
94      public void setDataDirectory(String dataDirectory) {
95          this.dataDirectory = dataDirectory;
96      }
97  
98      /**
99       * Get the value of failOnError.
100      *
101      * @return the value of failOnError
102      */
103     public boolean isFailOnError() {
104         return failOnError;
105     }
106 
107     /**
108      * Set the value of failOnError.
109      *
110      * @param failOnError new value of failOnError
111      */
112     public void setFailOnError(boolean failOnError) {
113         this.failOnError = failOnError;
114     }
115 
116     /**
117      * Get the value of hostedSuppressionsUrl.
118      *
119      * @return the value of hostedSuppressionsUrl
120      */
121     public String getHostedSuppressionsUrl() {
122         return hostedSuppressionsUrl;
123     }
124 
125     /**
126      * Set the value of hostedSuppressionsUrl.
127      *
128      * @param hostedSuppressionsUrl new value of hostedSuppressionsUrl
129      */
130     public void setHostedSuppressionsUrl(final String hostedSuppressionsUrl) {
131         this.hostedSuppressionsUrl = hostedSuppressionsUrl;
132     }
133 
134     /**
135      * Sets the
136      * {@link Thread#getContextClassLoader() Thread Context Class Loader} to the
137      * one for this class, and then calls
138      * {@link #executeWithContextClassloader()}. This is done because the JCS
139      * cache needs to have the Thread Context Class Loader set to something that
140      * can resolve it's classes. Other build tools do this by default but Ant
141      * does not.
142      *
143      * @throws BuildException throws if there is a problem. See
144      * {@link #executeWithContextClassloader()} for details
145      */
146     @Override
147     public final void execute() throws BuildException {
148         muteNoisyLoggers();
149         final ClassLoader current = Thread.currentThread().getContextClassLoader();
150         try {
151             Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
152 
153             executeWithContextClassloader();
154         } finally {
155             Thread.currentThread().setContextClassLoader(current);
156         }
157     }
158 
159     /**
160      * Hacky method of muting the noisy logging from JCS.
161      */
162     private void muteNoisyLoggers() {
163         System.setProperty("jcs.logSystem", "slf4j");
164         Slf4jAdapter.muteLogging(true);
165 
166         final String[] noisyLoggers = {
167             "org.apache.hc"
168         };
169         for (String loggerName : noisyLoggers) {
170             System.setProperty("org.slf4j.simpleLogger.log." + loggerName, "error");
171         }
172     }
173 
174     /**
175      * Executes the dependency-check purge to delete the existing local copy of
176      * the NVD CVE data.
177      *
178      * @throws BuildException thrown if there is a problem deleting the file(s)
179      */
180     //see note on `Check.dealWithReferences()` for information on this suppression
181     @SuppressWarnings("squid:RedundantThrowsDeclarationCheck")
182     protected void executeWithContextClassloader() throws BuildException {
183         populateSettings();
184         try {
185             Downloader.getInstance().configure(settings);
186         } catch (InvalidSettingException e) {
187             throw new BuildException(e);
188         }
189         try (Engine engine = new Engine(Engine.Mode.EVIDENCE_PROCESSING, getSettings())) {
190             engine.purge();
191         } finally {
192             settings.cleanup(true);
193         }
194     }
195 
196     /**
197      * Takes the properties supplied and updates the dependency-check settings.
198      * Additionally, this sets the system properties required to change the
199      * proxy server, port, and connection timeout.
200      *
201      * @throws BuildException thrown if the properties file cannot be read.
202      */
203     //see note on `Check.dealWithReferences()` for information on this suppression
204     @SuppressWarnings("squid:RedundantThrowsDeclarationCheck")
205     protected void populateSettings() throws BuildException {
206         settings = new Settings();
207         try (InputStream taskProperties = this.getClass().getClassLoader().getResourceAsStream(PROPERTIES_FILE)) {
208             settings.mergeProperties(taskProperties);
209         } catch (IOException ex) {
210             final String msg = "Unable to load the dependency-check ant task.properties file.";
211             if (this.failOnError) {
212                 throw new BuildException(msg, ex);
213             }
214             log(msg, ex, Project.MSG_WARN);
215         }
216         settings.setStringIfNotEmpty(Settings.KEYS.HOSTED_SUPPRESSIONS_URL, hostedSuppressionsUrl);
217         if (dataDirectory != null) {
218             settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDirectory);
219         } else {
220             final File jarPath = new File(Purge.class.getProtectionDomain().getCodeSource().getLocation().getPath());
221             final File base = jarPath.getParentFile();
222             final String sub = settings.getString(Settings.KEYS.DATA_DIRECTORY);
223             final File dataDir = new File(base, sub);
224             settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDir.getAbsolutePath());
225         }
226     }
227 }