Autopsy  4.21.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
ReportGenerator.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2013-2022 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.report.infrastructure;
20 
27 import java.awt.event.ActionEvent;
28 import java.awt.event.ActionListener;
29 import java.awt.event.WindowAdapter;
30 import java.awt.event.WindowEvent;
31 import java.io.File;
32 import java.io.IOException;
33 import java.text.DateFormat;
34 import java.text.SimpleDateFormat;
35 import java.util.ArrayList;
36 import java.util.Collections;
37 import java.util.Date;
38 import java.util.HashMap;
39 import java.util.List;
40 import java.util.Map;
41 import java.util.Map.Entry;
42 import java.util.logging.Level;
43 import javax.swing.JDialog;
44 import org.openide.filesystems.FileUtil;
45 import org.openide.util.NbBundle;
46 import org.openide.windows.WindowManager;
54 import org.sleuthkit.datamodel.AbstractFile;
55 import org.sleuthkit.datamodel.SleuthkitCase;
56 import org.sleuthkit.datamodel.TskCoreException;
57 import org.sleuthkit.datamodel.TskData;
58 
63 public class ReportGenerator {
64 
65  private static final Logger logger = Logger.getLogger(ReportGenerator.class.getName());
67  private final ReportGenerationPanel reportGenerationPanel;
68  private static final String REPORT_PATH_FMT_STR = "%s" + File.separator + "%s %s %s" + File.separator;
69  private final String configName;
70  private static final String REPORTS_DIR = "Reports"; //NON-NLS
71  private List<String> errorList = new ArrayList<>();
72 
79  public static String getReportsDirectory() {
80  return REPORTS_DIR;
81  }
82 
87  private void displayReportErrors() {
88  if (!errorList.isEmpty()) {
89  String errorString = "";
90  for (String error : errorList) {
91  errorString += error + "\n";
92  }
93  progressIndicator.updateStatusLabel(errorString);
94  }
95  }
96 
105  public ReportGenerator(String configName, ReportProgressIndicator progressIndicator) {
106  this.progressIndicator = progressIndicator;
107  this.reportGenerationPanel = null;
108  this.configName = configName;
109  }
110 
119  ReportGenerator(String configName, ReportGenerationPanel panel) {
120  this.reportGenerationPanel = panel;
121  this.progressIndicator = panel.getProgressPanel();
122  this.configName = configName;
123  }
124 
133  // load all report modules
134  Map<String, ReportModule> modules = new HashMap<>();
135  for (TableReportModule module : ReportModuleLoader.getTableReportModules()) {
136  modules.put(FactoryClassNameNormalizer.normalize(module.getClass().getCanonicalName()), module);
137  }
138 
139  for (GeneralReportModule module : ReportModuleLoader.getGeneralReportModules()) {
140  modules.put(FactoryClassNameNormalizer.normalize(module.getClass().getCanonicalName()), module);
141  }
142 
143  for (FileReportModule module : ReportModuleLoader.getFileReportModules()) {
144  modules.put(FactoryClassNameNormalizer.normalize(module.getClass().getCanonicalName()), module);
145  }
146 
147  // special case for PortableCaseReportModule
148  modules.put(FactoryClassNameNormalizer.normalize(PortableCaseReportModule.class.getCanonicalName()), new PortableCaseReportModule());
149 
150  generateReports(modules);
151  }
152 
153  @NbBundle.Messages({
154  "ReportGenerator.error.noReportModules=No report modules found",
155  "# {0} - report configuration name", "ReportGenerator.error.unableToLoadConfig=Unable to load reporting configuration {0}.",
156  "# {0} - report module name", "ReportGenerator.error.moduleNotFound=Report module {0} not found",
157  "# {0} - report module name", "ReportGenerator.error.noTableReportSettings=No table report settings for report module {0}",
158  "# {0} - report module name", "ReportGenerator.error.noFileReportSettings=No file report settings for report module {0}",
159  "# {0} - report module name", "ReportGenerator.error.invalidSettings=Invalid settings for report module {0}",
160  "# {0} - report module name", "ReportGenerator.error.unsupportedType=Report module {0} has unsupported report module type",
161  "# {0} - report module name", "ReportGenerator.error.exception=Exception while running report module {0}"})
173  public void generateReports(Map<String, ReportModule> modules) throws ReportGenerationException {
174 
175  if (modules == null || modules.isEmpty()) {
176  logger.log(Level.SEVERE, Bundle.ReportGenerator_error_noReportModules());
177  progressIndicator.updateStatusLabel(Bundle.ReportGenerator_error_noReportModules());
178  throw new ReportGenerationException(Bundle.ReportGenerator_error_noReportModules());
179  }
180 
181  ReportingConfig config = null;
182  try {
183  config = ReportingConfigLoader.loadConfig(configName);
184  } catch (ReportConfigException ex) {
185  logger.log(Level.SEVERE, Bundle.ReportGenerator_error_unableToLoadConfig(configName), ex);
186  progressIndicator.updateStatusLabel(Bundle.ReportGenerator_error_unableToLoadConfig(configName));
187  throw new ReportGenerationException(Bundle.ReportGenerator_error_unableToLoadConfig(configName));
188  }
189 
190  if (config == null) {
191  logger.log(Level.SEVERE, Bundle.ReportGenerator_error_unableToLoadConfig(configName));
192  progressIndicator.updateStatusLabel(Bundle.ReportGenerator_error_unableToLoadConfig(configName));
193  throw new ReportGenerationException(Bundle.ReportGenerator_error_unableToLoadConfig(configName));
194  }
195 
196  try {
197  // generate reports for enabled modules
198  for (Map.Entry<String, ReportModuleConfig> entry : config.getModuleConfigs().entrySet()) {
199  ReportModuleConfig moduleConfig = entry.getValue();
200  if (moduleConfig == null || !moduleConfig.isEnabled()) {
201  continue;
202  }
203 
204  // found enabled module
205  String moduleName = entry.getKey();
206  ReportModule module = modules.get(moduleName);
207  if (module == null) {
208  logger.log(Level.SEVERE, Bundle.ReportGenerator_error_moduleNotFound(moduleName));
209  progressIndicator.updateStatusLabel(Bundle.ReportGenerator_error_moduleNotFound(moduleName));
210  continue;
211  }
212 
213  // get persisted module settings
214  ReportModuleSettings settings = moduleConfig.getModuleSettings();
215  if (settings == null) {
216  // use default configuration for this module
217  settings = module.getDefaultConfiguration();
218  }
219 
220  // set module configuration
221  module.setConfiguration(settings);
222 
223  try {
224  // generate report according to report module type
225  if (module instanceof GeneralReportModule) {
226 
227  // generate report
228  generateGeneralReport((GeneralReportModule) module, config.getGeneralReportSettings());
229 
230  } else if (module instanceof TableReportModule) {
231 
232  // get table report settings
233  TableReportSettings tableSettings = config.getTableReportSettings();
234  if (tableSettings == null) {
235  logger.log(Level.SEVERE, Bundle.ReportGenerator_error_noTableReportSettings(moduleName));
236  progressIndicator.updateStatusLabel(Bundle.ReportGenerator_error_noTableReportSettings(moduleName));
237  continue;
238  }
239 
240  generateTableReport((TableReportModule) module, tableSettings); //NON-NLS
241 
242  } else if (module instanceof FileReportModule) {
243 
244  // get file report settings
245  FileReportSettings fileSettings = config.getFileReportSettings();
246  if (fileSettings == null) {
247  logger.log(Level.SEVERE, Bundle.ReportGenerator_error_noFileReportSettings(moduleName));
248  progressIndicator.updateStatusLabel(Bundle.ReportGenerator_error_noFileReportSettings(moduleName));
249  continue;
250  }
251 
252  generateFileListReport((FileReportModule) module, fileSettings); //NON-NLS
253 
254  } else if (module instanceof PortableCaseReportModule) {
255  // get report settings
256  if (settings instanceof NoReportModuleSettings) {
257  settings = new PortableCaseReportModuleSettings();
258  } else if (!(settings instanceof PortableCaseReportModuleSettings)) {
259  logger.log(Level.SEVERE, Bundle.ReportGenerator_error_invalidSettings(moduleName));
260  progressIndicator.updateStatusLabel(Bundle.ReportGenerator_error_invalidSettings(moduleName));
261  continue;
262  }
263 
264  generatePortableCaseReport((PortableCaseReportModule) module, (PortableCaseReportModuleSettings) settings);
265 
266  } else {
267  logger.log(Level.SEVERE, Bundle.ReportGenerator_error_unsupportedType(moduleName));
268  progressIndicator.updateStatusLabel(Bundle.ReportGenerator_error_unsupportedType(moduleName));
269  }
270  } catch (IOException e) {
271  logger.log(Level.SEVERE, Bundle.ReportGenerator_error_exception(moduleName));
272  progressIndicator.updateStatusLabel(Bundle.ReportGenerator_error_exception(moduleName));
273  }
274  }
275  } finally {
277  errorList.clear();
278  }
279  }
280 
285  void displayProgressPanel() {
286  if (reportGenerationPanel == null) {
287  return;
288  }
289 
290  final JDialog dialog = new JDialog(WindowManager.getDefault().getMainWindow(), true);
291  dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
292  dialog.setTitle(NbBundle.getMessage(this.getClass(), "ReportGenerator.displayProgress.title.text"));
293  dialog.add(this.reportGenerationPanel);
294  dialog.pack();
295 
296  reportGenerationPanel.addCloseAction(new ActionListener() {
297  @Override
298  public void actionPerformed(ActionEvent e) {
299  dialog.dispose();
300  }
301  });
302 
303  dialog.addWindowListener(new WindowAdapter() {
304  @Override
305  public void windowClosing(WindowEvent e) {
306  reportGenerationPanel.close();
307  }
308  });
309 
310  dialog.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
311  dialog.setVisible(true);
312  }
313 
317  private void generateGeneralReport(GeneralReportModule generalReportModule, GeneralReportSettings reportSettings) throws IOException {
318  if (generalReportModule != null) {
319  String reportDir = createReportDirectory(generalReportModule);
320  setupProgressPanel(generalReportModule, reportDir);
321  reportSettings.setReportDirectoryPath(reportDir);
322  generalReportModule.generateReport(reportSettings, progressIndicator);
323  }
324  }
325 
332  private void generateTableReport(TableReportModule tableReport, TableReportSettings tableReportSettings) throws IOException {
333  if (tableReport != null && tableReportSettings != null && null != tableReportSettings.getArtifactSelections()) {
334  String reportDir = createReportDirectory(tableReport);
335  setupProgressPanel(tableReport, reportDir);
336  tableReport.startReport(reportDir);
337  TableReportGenerator generator = new TableReportGenerator(tableReportSettings, progressIndicator, tableReport);
338  generator.execute();
339  tableReport.endReport();
340 
341  // finish progress, wrap up
342  errorList = generator.getErrorList();
343 
344  // if error list is empty, the operation has completed successfully. If not there is an error
345  ReportProgressPanel.ReportStatus finalStatus = (errorList == null || errorList.isEmpty())
348 
349  progressIndicator.complete(finalStatus);
350  }
351  }
352 
359  private void generateFileListReport(FileReportModule fileReportModule, FileReportSettings fileReportSettings) throws IOException {
360  if (fileReportModule != null && fileReportSettings != null && null != fileReportSettings.getFileProperties()) {
361  String reportDir = createReportDirectory(fileReportModule);
362  List<FileReportDataTypes> enabled = new ArrayList<>();
363  for (Entry<FileReportDataTypes, Boolean> e : fileReportSettings.getFileProperties().entrySet()) {
364  if (e.getValue()) {
365  enabled.add(e.getKey());
366  }
367  }
368  setupProgressPanel(fileReportModule, reportDir);
369  if (progressIndicator.getStatus() != ReportStatus.CANCELED) {
370  progressIndicator.start();
371  progressIndicator.updateStatusLabel(
372  NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.queryingDb.text"));
373  }
374 
375  List<AbstractFile> files = getFiles();
376  int numFiles = files.size();
377  if (progressIndicator.getStatus() != ReportStatus.CANCELED) {
378  fileReportModule.startReport(reportDir);
379  fileReportModule.startTable(enabled);
380  }
381  progressIndicator.setIndeterminate(false);
382  progressIndicator.setMaximumProgress(numFiles);
383 
384  int i = 0;
385  // Add files to report.
386  for (AbstractFile file : files) {
387  if (shouldFilterFromReport(file, fileReportSettings)) {
388  continue;
389  }
390 
391  // Check to see if any reports have been cancelled.
392  if (progressIndicator.getStatus() == ReportStatus.CANCELED) {
393  return;
394  } else {
395  fileReportModule.addRow(file, enabled);
396  progressIndicator.increment();
397  }
398 
399  if ((i % 100) == 0) {
400  progressIndicator.updateStatusLabel(
401  NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processingFile.text",
402  file.getName()));
403  }
404  i++;
405  }
406 
407  fileReportModule.endTable();
408  fileReportModule.endReport();
409  progressIndicator.complete(ReportStatus.COMPLETE);
410  }
411  }
412 
413  private boolean shouldFilterFromReport(AbstractFile file, FileReportSettings fileReportSettings) {
414  if (fileReportSettings.getSelectedDataSources() == null) {
415  return false;
416  }
417  // Filter if the data source id is not in the list to process
418  return !fileReportSettings.getSelectedDataSources().contains(file.getDataSourceObjectId());
419  }
420 
424  private void generatePortableCaseReport(PortableCaseReportModule portableCaseReportModule, PortableCaseReportModuleSettings settings) throws IOException {
425  if (portableCaseReportModule != null) {
426  String reportDir = createReportDirectory(portableCaseReportModule);
427  setupProgressPanel(portableCaseReportModule, reportDir);
428  portableCaseReportModule.generateReport(reportDir, settings, progressIndicator);
429  }
430  }
431 
437  private List<AbstractFile> getFiles() {
438  List<AbstractFile> absFiles;
439  try {
440  SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
441  absFiles = skCase.findAllFilesWhere("meta_type != " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()); //NON-NLS
442  return absFiles;
443  } catch (TskCoreException | NoCurrentCaseException ex) {
444  progressIndicator.updateStatusLabel(NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorText") + ex.getLocalizedMessage());
445  logger.log(Level.SEVERE, "failed to generate reports. Unable to get all files in the image.", ex); //NON-NLS
446  return Collections.<AbstractFile>emptyList();
447  }
448  }
449 
450  private void setupProgressPanel(ReportModule module, String reportDir) {
451  if (reportGenerationPanel != null) {
452  String reportFilePath = module.getRelativeFilePath();
453  if (reportFilePath == null) {
454  reportGenerationPanel.addReport(module.getName(), null);
455  } else if (reportFilePath.isEmpty()) {
456  reportGenerationPanel.addReport(module.getName(), reportDir);
457  } else {
458  reportGenerationPanel.addReport(module.getName(), reportDir + reportFilePath);
459  }
460  }
461  }
462 
463  private static String createReportDirectory(ReportModule module) throws IOException {
464  Case currentCase;
465  try {
466  currentCase = Case.getCurrentCaseThrows();
467  } catch (NoCurrentCaseException ex) {
468  throw new IOException("Exception while getting open case.", ex);
469  }
470  // Create the root reports directory path of the form: <CASE DIRECTORY>/Reports/<Case fileName> <Timestamp>/
471  DateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy-HH-mm-ss");
472  Date date = new Date();
473  String dateNoTime = dateFormat.format(date);
474  String reportPath = String.format(REPORT_PATH_FMT_STR, currentCase.getReportDirectory(), currentCase.getDisplayName(), module.getName(), dateNoTime);
475  // Create the root reports directory.
476  try {
477  FileUtil.createFolder(new File(reportPath));
478  } catch (IOException ex) {
479  throw new IOException("Failed to make report folder, unable to generate reports.", ex);
480  }
481  return reportPath;
482  }
483 }
void generatePortableCaseReport(PortableCaseReportModule portableCaseReportModule, PortableCaseReportModuleSettings settings)
void generateTableReport(TableReportModule tableReport, TableReportSettings tableReportSettings)
void generateFileListReport(FileReportModule fileReportModule, FileReportSettings fileReportSettings)
default ReportModuleSettings getDefaultConfiguration()
ReportGenerator(String configName, ReportProgressIndicator progressIndicator)
default void setConfiguration(ReportModuleSettings settings)
void generateGeneralReport(GeneralReportModule generalReportModule, GeneralReportSettings reportSettings)
boolean shouldFilterFromReport(AbstractFile file, FileReportSettings fileReportSettings)
void generateReports(Map< String, ReportModule > modules)
void setupProgressPanel(ReportModule module, String reportDir)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124

Copyright © 2012-2022 Basis Technology. Generated on: Tue Feb 6 2024
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.