Autopsy 4.22.1
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 */
19package org.sleuthkit.autopsy.report.infrastructure;
20
21import org.sleuthkit.autopsy.report.modules.portablecase.PortableCaseReportModuleSettings;
22import org.sleuthkit.autopsy.report.modules.portablecase.PortableCaseReportModule;
23import org.sleuthkit.autopsy.report.NoReportModuleSettings;
24import org.sleuthkit.autopsy.report.ReportModule;
25import org.sleuthkit.autopsy.report.ReportModuleSettings;
26import org.sleuthkit.autopsy.report.GeneralReportModule;
27import java.awt.event.ActionEvent;
28import java.awt.event.ActionListener;
29import java.awt.event.WindowAdapter;
30import java.awt.event.WindowEvent;
31import java.io.File;
32import java.io.IOException;
33import java.text.DateFormat;
34import java.text.SimpleDateFormat;
35import java.util.ArrayList;
36import java.util.Collections;
37import java.util.Date;
38import java.util.HashMap;
39import java.util.List;
40import java.util.Map;
41import java.util.Map.Entry;
42import java.util.logging.Level;
43import javax.swing.JDialog;
44import org.openide.filesystems.FileUtil;
45import org.openide.util.NbBundle;
46import org.openide.windows.WindowManager;
47import org.sleuthkit.autopsy.casemodule.Case;
48import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
49import org.sleuthkit.autopsy.coreutils.Logger;
50import org.sleuthkit.autopsy.python.FactoryClassNameNormalizer;
51import org.sleuthkit.autopsy.report.GeneralReportSettings;
52import org.sleuthkit.autopsy.report.ReportProgressPanel;
53import org.sleuthkit.autopsy.report.ReportProgressPanel.ReportStatus;
54import org.sleuthkit.datamodel.AbstractFile;
55import org.sleuthkit.datamodel.SleuthkitCase;
56import org.sleuthkit.datamodel.TskCoreException;
57import org.sleuthkit.datamodel.TskData;
58
63public 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
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
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
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();
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}
synchronized static Logger getLogger(String name)
Definition Logger.java:124
void generateReports(Map< String, ReportModule > modules)
boolean shouldFilterFromReport(AbstractFile file, FileReportSettings fileReportSettings)
void setupProgressPanel(ReportModule module, String reportDir)
void generateTableReport(TableReportModule tableReport, TableReportSettings tableReportSettings)
ReportGenerator(String configName, ReportProgressIndicator progressIndicator)
void generateGeneralReport(GeneralReportModule generalReportModule, GeneralReportSettings reportSettings)
void generateFileListReport(FileReportModule fileReportModule, FileReportSettings fileReportSettings)
void generatePortableCaseReport(PortableCaseReportModule portableCaseReportModule, PortableCaseReportModuleSettings settings)
default void setConfiguration(ReportModuleSettings settings)
default ReportModuleSettings getDefaultConfiguration()

Copyright © 2012-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.