From f5fae2c1c63486fb877db34369a897248e74f50d Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Mon, 2 May 2016 16:20:33 -0400 Subject: [PATCH 001/172] Started moving to one report in reports code. --- .../autopsy/report/ReportGenerator.java | 412 ++++++++---------- .../autopsy/report/ReportVisualPanel1.java | 24 +- .../autopsy/report/ReportWizardAction.java | 6 +- .../autopsy/report/ReportWizardPanel1.java | 15 +- 4 files changed, 209 insertions(+), 248 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java index 1f49588837..c0c72447d6 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java @@ -34,7 +34,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -53,7 +52,6 @@ import javax.swing.SwingWorker; import org.openide.filesystems.FileUtil; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.EscapeUtil; import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; @@ -66,13 +64,13 @@ import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; +import org.sleuthkit.datamodel.BlackboardAttribute.Type; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; -import org.sleuthkit.datamodel.BlackboardAttribute.Type; /** * Instances of this class use GeneralReportModules, TableReportModules and @@ -87,9 +85,10 @@ class ReportGenerator { private Case currentCase = Case.getCurrentCase(); private SleuthkitCase skCase = currentCase.getSleuthkitCase(); - private Map tableProgress; - private Map generalProgress; - private Map fileProgress; + private TableReportModule tableReportModule; + private GeneralReportModule generalReportModule; + private FileReportModule fileReportModule; + private ReportProgressPanel progressPanel; private Map> columnHeaderMap; private String reportPath; @@ -117,7 +116,7 @@ class ReportGenerator { } } - ReportGenerator(Map tableModuleStates, Map generalModuleStates, Map fileListModuleStates) { + ReportGenerator(TableReportModule tableModuleStates, GeneralReportModule generalModuleStates, FileReportModule fileListModuleStates) { // Create the root reports directory path of the form: /Reports/ / DateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy-HH-mm-ss"); Date date = new Date(); @@ -136,9 +135,6 @@ class ReportGenerator { } // Initialize the progress panels - generalProgress = new HashMap<>(); - tableProgress = new HashMap<>(); - fileProgress = new HashMap<>(); setupProgressPanels(tableModuleStates, generalModuleStates, fileListModuleStates); this.columnHeaderMap = new HashMap<>(); } @@ -147,53 +143,44 @@ class ReportGenerator { * Create a ReportProgressPanel for each report generation module selected * by the user. * - * @param tableModuleStates The enabled/disabled state of each + * @param tableModule The enabled/disabled state of each * TableReportModule * @param generalModuleStates The enabled/disabled state of each * GeneralReportModule * @param fileListModuleStates The enabled/disabled state of each * FileReportModule */ - private void setupProgressPanels(Map tableModuleStates, Map generalModuleStates, Map fileListModuleStates) { - if (null != tableModuleStates) { - for (Entry entry : tableModuleStates.entrySet()) { - if (entry.getValue()) { - TableReportModule module = entry.getKey(); - String reportFilePath = module.getRelativeFilePath(); - if (!reportFilePath.isEmpty()) { - tableProgress.put(module, panel.addReport(module.getName(), reportPath + reportFilePath)); - } else { - tableProgress.put(module, panel.addReport(module.getName(), null)); - } - } + private void setupProgressPanels(TableReportModule tableModule, GeneralReportModule generalModule, FileReportModule fileListModule) { + if (null != tableModule) { + String reportFilePath = tableModule.getRelativeFilePath(); + if (!reportFilePath.isEmpty()) { + this.tableReportModule = tableModule; + this.progressPanel = panel.addReport(tableModule.getName(), reportPath + reportFilePath); + } else { + this.tableReportModule = tableModule; + this.progressPanel = panel.addReport(tableModule.getName(), null); } } - if (null != generalModuleStates) { - for (Entry entry : generalModuleStates.entrySet()) { - if (entry.getValue()) { - GeneralReportModule module = entry.getKey(); - String reportFilePath = module.getRelativeFilePath(); - if (!reportFilePath.isEmpty()) { - generalProgress.put(module, panel.addReport(module.getName(), reportPath + reportFilePath)); - } else { - generalProgress.put(module, panel.addReport(module.getName(), null)); - } - } + if (null != generalModule) { + String reportFilePath = generalModule.getRelativeFilePath(); + if (!reportFilePath.isEmpty()) { + this.generalReportModule = generalModule; + this.progressPanel = panel.addReport(generalModule.getName(), reportPath + reportFilePath); + } else { + this.generalReportModule = generalModule; + this.progressPanel = panel.addReport(generalModule.getName(), null); } } - if (null != fileListModuleStates) { - for (Entry entry : fileListModuleStates.entrySet()) { - if (entry.getValue()) { - FileReportModule module = entry.getKey(); - String reportFilePath = module.getRelativeFilePath(); - if (!reportFilePath.isEmpty()) { - fileProgress.put(module, panel.addReport(module.getName(), reportPath + reportFilePath)); - } else { - fileProgress.put(module, panel.addReport(module.getName(), null)); - } - } + if (null != fileListModule) { + String reportFilePath = fileListModule.getRelativeFilePath(); + if (!reportFilePath.isEmpty()) { + fileReportModule = fileListModule; + this.progressPanel = panel.addReport(fileListModule.getName(), reportPath + reportFilePath); + } else { + fileReportModule = fileListModule; + this.progressPanel = panel.addReport(fileListModule.getName(), null); } } } @@ -249,7 +236,7 @@ class ReportGenerator { * to be included in the report */ public void generateTableReports(Map artifactTypeSelections, Map tagNameSelections) { - if (!tableProgress.isEmpty() && null != artifactTypeSelections) { + if (tableReportModule != null && null != artifactTypeSelections) { TableReportsWorker worker = new TableReportsWorker(artifactTypeSelections, tagNameSelections); worker.execute(); } @@ -262,7 +249,7 @@ class ReportGenerator { * file in the report. */ public void generateFileListReports(Map enabledInfo) { - if (!fileProgress.isEmpty() && null != enabledInfo) { + if (fileReportModule != null && null != enabledInfo) { List enabled = new ArrayList<>(); for (Entry e : enabledInfo.entrySet()) { if (e.getValue()) { @@ -271,6 +258,7 @@ class ReportGenerator { } FileReportsWorker worker = new FileReportsWorker(enabled); worker.execute(); + } } @@ -281,11 +269,8 @@ class ReportGenerator { @Override protected Integer doInBackground() throws Exception { - for (Entry entry : generalProgress.entrySet()) { - GeneralReportModule module = entry.getKey(); - if (generalProgress.get(module).getStatus() != ReportStatus.CANCELED) { - module.generateReport(reportPath, generalProgress.get(module)); - } + if (progressPanel.getStatus() != ReportStatus.CANCELED) { + generalReportModule.generateReport(reportPath, progressPanel); } return 0; } @@ -316,68 +301,54 @@ class ReportGenerator { private class FileReportsWorker extends SwingWorker { private List enabledInfo = Arrays.asList(FileReportDataTypes.values()); - private List fileModules = new ArrayList<>(); FileReportsWorker(List enabled) { enabledInfo = enabled; - for (Entry entry : fileProgress.entrySet()) { - fileModules.add(entry.getKey()); - } } @Override protected Integer doInBackground() throws Exception { - for (FileReportModule module : fileModules) { - ReportProgressPanel progress = fileProgress.get(module); - if (progress.getStatus() != ReportStatus.CANCELED) { - progress.start(); - progress.updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.queryingDb.text")); - } + if (progressPanel.getStatus() != ReportStatus.CANCELED) { + progressPanel.start(); + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.queryingDb.text")); } List files = getFiles(); int numFiles = files.size(); - for (FileReportModule module : fileModules) { - module.startReport(reportPath); - module.startTable(enabledInfo); - fileProgress.get(module).setIndeterminate(false); - fileProgress.get(module).setMaximumProgress(numFiles); + if (fileReportModule != null) { + fileReportModule.startReport(reportPath); + fileReportModule.startTable(enabledInfo); } + progressPanel.setIndeterminate(false); + progressPanel.setMaximumProgress(numFiles); int i = 0; // Add files to report. for (AbstractFile file : files) { // Check to see if any reports have been cancelled. - if (fileModules.isEmpty()) { + if (fileReportModule == null) { break; } // Remove cancelled reports, add files to report otherwise. - Iterator iter = fileModules.iterator(); - while (iter.hasNext()) { - FileReportModule module = iter.next(); - ReportProgressPanel progress = fileProgress.get(module); - if (progress.getStatus() == ReportStatus.CANCELED) { - iter.remove(); - } else { - module.addRow(file, enabledInfo); - progress.increment(); - } + if (progressPanel.getStatus() == ReportStatus.CANCELED) { + fileReportModule = null; + } else { + fileReportModule.addRow(file, enabledInfo); + progressPanel.increment(); + } - if ((i % 100) == 0) { - progress.updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processingFile.text", - file.getName())); - } + if ((i % 100) == 0) { + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processingFile.text", + file.getName())); } i++; } - for (FileReportModule module : fileModules) { - module.endTable(); - module.endReport(); - fileProgress.get(module).complete(ReportStatus.COMPLETE); - } + fileReportModule.endTable(); + fileReportModule.endReport(); + progressPanel.complete(ReportStatus.COMPLETE); return 0; } @@ -428,17 +399,12 @@ class ReportGenerator { */ private class TableReportsWorker extends SwingWorker { - private List tableModules = new ArrayList<>(); private List artifactTypes = new ArrayList<>(); private HashSet tagNamesFilter = new HashSet<>(); private List images = new ArrayList<>(); TableReportsWorker(Map artifactTypeSelections, Map tagNameSelections) { - // Get the report modules selected by the user. - for (Entry entry : tableProgress.entrySet()) { - tableModules.add(entry.getKey()); - } // Get the artifact types selected by the user. for (Entry entry : artifactTypeSelections.entrySet()) { @@ -460,16 +426,13 @@ class ReportGenerator { @Override protected Integer doInBackground() throws Exception { // Start the progress indicators for each active TableReportModule. - for (TableReportModule module : tableModules) { - ReportProgressPanel progress = tableProgress.get(module); - if (progress.getStatus() != ReportStatus.CANCELED) { - module.startReport(reportPath); - progress.start(); - progress.setIndeterminate(false); - progress.setMaximumProgress(this.artifactTypes.size() + 2); // +2 for content and blackboard artifact tags - } + if (progressPanel.getStatus() == ReportStatus.CANCELED) { + } else { + tableReportModule.startReport(reportPath); + progressPanel.start(); + progressPanel.setIndeterminate(false); + progressPanel.setMaximumProgress(this.artifactTypes.size() + 2); // +2 for content and blackboard artifact tags } - // report on the blackboard results makeBlackboardArtifactTables(); @@ -481,10 +444,8 @@ class ReportGenerator { makeThumbnailTable(); // finish progress, wrap up - for (TableReportModule module : tableModules) { - tableProgress.get(module).complete(ReportStatus.COMPLETE); - module.endReport(); - } + progressPanel.complete(ReportStatus.COMPLETE); + tableReportModule.endReport(); return 0; } @@ -504,22 +465,20 @@ class ReportGenerator { for (BlackboardArtifact.Type type : artifactTypes) { // Check for cancellaton. removeCancelledTableReportModules(); - if (tableModules.isEmpty()) { + if (tableReportModule == null) { return; } - for (TableReportModule module : tableModules) { - tableProgress.get(module).updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", - type.getDisplayName())); - } + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", + type.getDisplayName())); // Keyword hits and hashset hit artifacts get special handling. if (type.getTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { - writeKeywordHits(tableModules, comment.toString(), tagNamesFilter); + writeKeywordHits(tableReportModule, comment.toString(), tagNamesFilter); continue; } else if (type.getTypeID() == ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) { - writeHashsetHits(tableModules, comment.toString(), tagNamesFilter); + writeHashsetHits(tableReportModule, comment.toString(), tagNamesFilter); continue; } @@ -558,30 +517,22 @@ class ReportGenerator { columnHeaderNames.add(currColumn.getColumnHeader()); } - for (TableReportModule module : tableModules) { - module.startDataType(type.getDisplayName(), comment.toString()); - module.startTable(columnHeaderNames); - } + tableReportModule.startDataType(type.getDisplayName(), comment.toString()); + tableReportModule.startTable(columnHeaderNames); for (ArtifactData artifactData : artifactList) { - // Add the row data to all of the reports. - for (TableReportModule module : tableModules) { - - // Get the row data for this artifact, and has the - // module add it. - List rowData = artifactData.getRow(); - if (rowData.isEmpty()) { - continue; - } - - module.addRow(rowData); + // Get the row data for this artifact, and has the + // module add it. + List rowData = artifactData.getRow(); + if (rowData.isEmpty()) { + continue; } + + tableReportModule.addRow(rowData); } // Finish up this data type - for (TableReportModule module : tableModules) { - tableProgress.get(module).increment(); - module.endTable(); - module.endDataType(); - } + progressPanel.increment(); + tableReportModule.endTable(); + tableReportModule.endDataType(); } } @@ -592,7 +543,7 @@ class ReportGenerator { private void makeContentTagsTables() { // Check for cancellaton. removeCancelledTableReportModules(); - if (tableModules.isEmpty()) { + if (tableReportModule == null) { return; } @@ -607,37 +558,35 @@ class ReportGenerator { } // Tell the modules reporting on content tags is beginning. - for (TableReportModule module : tableModules) { - // @@@ This casting is a tricky little workaround to allow the HTML report module to slip in a content hyperlink. - // @@@ Alos Using the obsolete ARTIFACT_TYPE.TSK_TAG_FILE is also an expedient hack. - tableProgress.get(module).updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", - ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName())); - ArrayList columnHeaders = new ArrayList<>(Arrays.asList( - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.tag"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.file"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.comment"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeModified"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeChanged"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeAccessed"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeCreated"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.size"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.hash"))); + // @@@ This casting is a tricky little workaround to allow the HTML report module to slip in a content hyperlink. + // @@@ Alos Using the obsolete ARTIFACT_TYPE.TSK_TAG_FILE is also an expedient hack. + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", + ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName())); + ArrayList columnHeaders = new ArrayList<>(Arrays.asList( + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.tag"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.file"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.comment"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeModified"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeChanged"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeAccessed"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeCreated"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.size"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.hash"))); - StringBuilder comment = new StringBuilder(); - if (!tagNamesFilter.isEmpty()) { - comment.append( - NbBundle.getMessage(this.getClass(), "ReportGenerator.makeContTagTab.taggedFiles.msg")); - comment.append(makeCommaSeparatedList(tagNamesFilter)); - } - if (module instanceof ReportHTML) { - ReportHTML htmlReportModule = (ReportHTML) module; - htmlReportModule.startDataType(ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName(), comment.toString()); - htmlReportModule.startContentTagsTable(columnHeaders); - } else { - module.startDataType(ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName(), comment.toString()); - module.startTable(columnHeaders); - } + StringBuilder comment = new StringBuilder(); + if (!tagNamesFilter.isEmpty()) { + comment.append( + NbBundle.getMessage(this.getClass(), "ReportGenerator.makeContTagTab.taggedFiles.msg")); + comment.append(makeCommaSeparatedList(tagNamesFilter)); + } + if (tableReportModule instanceof ReportHTML) { + ReportHTML htmlReportModule = (ReportHTML) tableReportModule; + htmlReportModule.startDataType(ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName(), comment.toString()); + htmlReportModule.startContentTagsTable(columnHeaders); + } else { + tableReportModule.startDataType(ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName(), comment.toString()); + tableReportModule.startTable(columnHeaders); } // Give the modules the rows for the content tags. @@ -667,14 +616,12 @@ class ReportGenerator { rowData.add(Long.toString(file.getSize())); rowData.add(file.getMd5Hash()); } - for (TableReportModule module : tableModules) { - // @@@ This casting is a tricky little workaround to allow the HTML report module to slip in a content hyperlink. - if (module instanceof ReportHTML) { - ReportHTML htmlReportModule = (ReportHTML) module; - htmlReportModule.addRowWithTaggedContentHyperlink(rowData, tag); - } else { - module.addRow(rowData); - } + // @@@ This casting is a tricky little workaround to allow the HTML report module to slip in a content hyperlink. + if (tableReportModule instanceof ReportHTML) { + ReportHTML htmlReportModule = (ReportHTML) tableReportModule; + htmlReportModule.addRowWithTaggedContentHyperlink(rowData, tag); + } else { + tableReportModule.addRow(rowData); } // see if it is for an image so that we later report on it @@ -682,11 +629,9 @@ class ReportGenerator { } // The the modules content tags reporting is ended. - for (TableReportModule module : tableModules) { - tableProgress.get(module).increment(); - module.endTable(); - module.endDataType(); - } + progressPanel.increment(); + tableReportModule.endTable(); + tableReportModule.endDataType(); } @Override @@ -715,7 +660,7 @@ class ReportGenerator { private void makeBlackboardArtifactTagsTables() { // Check for cancellaton. removeCancelledTableReportModules(); - if (tableModules.isEmpty()) { + if (tableReportModule == null) { return; } @@ -730,8 +675,7 @@ class ReportGenerator { // Tell the modules reporting on blackboard artifact tags data type is beginning. // @@@ Using the obsolete ARTIFACT_TYPE.TSK_TAG_ARTIFACT is an expedient hack. - for (TableReportModule module : tableModules) { - tableProgress.get(module).updateStatusLabel( + progressPanel.updateStatusLabel( NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getDisplayName())); StringBuilder comment = new StringBuilder(); @@ -746,7 +690,7 @@ class ReportGenerator { NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.tag"), NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.comment"), NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.srcFile")))); - } + // Give the modules the rows for the content tags. for (BlackboardArtifactTag tag : tags) { @@ -784,14 +728,9 @@ class ReportGenerator { } void removeCancelledTableReportModules() { - Iterator iter = tableModules.iterator(); - while (iter.hasNext()) { - TableReportModule module = iter.next(); - if (tableProgress.get(module).getStatus() == ReportStatus.CANCELED) { - iter.remove(); + if (progressPanel.getStatus() == ReportStatus.CANCELED) { + tableReportModule = null; } - } - } /** * Make a report for the files that were previously found to be images. @@ -876,7 +815,7 @@ class ReportGenerator { } } - /// @@@ Should move the methods specific to TableReportsWorker into that scope. +/// @@@ Should move the methods specific to TableReportsWorker into that scope. private Boolean failsTagFilter(HashSet tagNames, HashSet tagsNamesFilter) { if (null == tagsNamesFilter || tagsNamesFilter.isEmpty()) { return false; @@ -942,11 +881,16 @@ class ReportGenerator { orderByClause = "ORDER BY list ASC"; //NON-NLS } String keywordListQuery - = "SELECT att.value_text AS list " + //NON-NLS - "FROM blackboard_attributes AS att, blackboard_artifacts AS art " + //NON-NLS - "WHERE att.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + " " + //NON-NLS - "AND art.artifact_type_id = " + ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + " " + //NON-NLS - "AND att.artifact_id = art.artifact_id " + //NON-NLS + = "SELECT att.value_text AS list " + + //NON-NLS + "FROM blackboard_attributes AS att, blackboard_artifacts AS art " + + //NON-NLS + "WHERE att.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + " " + + //NON-NLS + "AND art.artifact_type_id = " + ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + " " + + //NON-NLS + "AND att.artifact_id = art.artifact_id " + + //NON-NLS "GROUP BY list " + orderByClause; //NON-NLS try (CaseDbQuery dbQuery = skCase.executeQuery(keywordListQuery)) { @@ -985,16 +929,26 @@ class ReportGenerator { } // Query for keywords, grouped by list String keywordsQuery - = "SELECT art.artifact_id, art.obj_id, att1.value_text AS keyword, att2.value_text AS preview, att3.value_text AS list, f.name AS name, f.parent_path AS parent_path " + //NON-NLS - "FROM blackboard_artifacts AS art, blackboard_attributes AS att1, blackboard_attributes AS att2, blackboard_attributes AS att3, tsk_files AS f " + //NON-NLS - "WHERE (att1.artifact_id = art.artifact_id) " + //NON-NLS - "AND (att2.artifact_id = art.artifact_id) " + //NON-NLS - "AND (att3.artifact_id = art.artifact_id) " + //NON-NLS - "AND (f.obj_id = art.obj_id) " + //NON-NLS - "AND (att1.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID() + ") " + //NON-NLS - "AND (att2.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW.getTypeID() + ") " + //NON-NLS - "AND (att3.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + ") " + //NON-NLS - "AND (art.artifact_type_id = " + ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + ") " + //NON-NLS + = "SELECT art.artifact_id, art.obj_id, att1.value_text AS keyword, att2.value_text AS preview, att3.value_text AS list, f.name AS name, f.parent_path AS parent_path " + + //NON-NLS + "FROM blackboard_artifacts AS art, blackboard_attributes AS att1, blackboard_attributes AS att2, blackboard_attributes AS att3, tsk_files AS f " + + //NON-NLS + "WHERE (att1.artifact_id = art.artifact_id) " + + //NON-NLS + "AND (att2.artifact_id = art.artifact_id) " + + //NON-NLS + "AND (att3.artifact_id = art.artifact_id) " + + //NON-NLS + "AND (f.obj_id = art.obj_id) " + + //NON-NLS + "AND (att1.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID() + ") " + + //NON-NLS + "AND (att2.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW.getTypeID() + ") " + + //NON-NLS + "AND (att3.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + ") " + + //NON-NLS + "AND (art.artifact_type_id = " + ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + ") " + + //NON-NLS orderByClause; //NON-NLS try (CaseDbQuery dbQuery = skCase.executeQuery(keywordsQuery)) { @@ -1106,11 +1060,16 @@ class ReportGenerator { orderByClause = "ORDER BY att.value_text ASC"; //NON-NLS } String hashsetsQuery - = "SELECT att.value_text AS list " + //NON-NLS - "FROM blackboard_attributes AS att, blackboard_artifacts AS art " + //NON-NLS - "WHERE att.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + " " + //NON-NLS - "AND art.artifact_type_id = " + ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() + " " + //NON-NLS - "AND att.artifact_id = art.artifact_id " + //NON-NLS + = "SELECT att.value_text AS list " + + //NON-NLS + "FROM blackboard_attributes AS att, blackboard_artifacts AS art " + + //NON-NLS + "WHERE att.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + " " + + //NON-NLS + "AND art.artifact_type_id = " + ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() + " " + + //NON-NLS + "AND att.artifact_id = art.artifact_id " + + //NON-NLS "GROUP BY list " + orderByClause; //NON-NLS try (CaseDbQuery dbQuery = skCase.executeQuery(hashsetsQuery)) { @@ -1143,12 +1102,18 @@ class ReportGenerator { orderByClause = "ORDER BY att.value_text ASC, f.parent_path ASC, f.name ASC, size ASC"; //NON-NLS } String hashsetHitsQuery - = "SELECT art.artifact_id, art.obj_id, att.value_text AS setname, f.name AS name, f.size AS size, f.parent_path AS parent_path " + //NON-NLS - "FROM blackboard_artifacts AS art, blackboard_attributes AS att, tsk_files AS f " + //NON-NLS - "WHERE (att.artifact_id = art.artifact_id) " + //NON-NLS - "AND (f.obj_id = art.obj_id) " + //NON-NLS - "AND (att.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + ") " + //NON-NLS - "AND (art.artifact_type_id = " + ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() + ") " + //NON-NLS + = "SELECT art.artifact_id, art.obj_id, att.value_text AS setname, f.name AS name, f.size AS size, f.parent_path AS parent_path " + + //NON-NLS + "FROM blackboard_artifacts AS art, blackboard_attributes AS att, tsk_files AS f " + + //NON-NLS + "WHERE (att.artifact_id = art.artifact_id) " + + //NON-NLS + "AND (f.obj_id = art.obj_id) " + + //NON-NLS + "AND (att.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + ") " + + //NON-NLS + "AND (art.artifact_type_id = " + ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() + ") " + + //NON-NLS orderByClause; //NON-NLS try (CaseDbQuery dbQuery = skCase.executeQuery(hashsetHitsQuery)) { @@ -1948,13 +1913,11 @@ class ReportGenerator { orderedRowData.addAll(Arrays.asList(attributeDataArray)); orderedRowData.add(makeCommaSeparatedList(getTags())); - } else { - if (ReportGenerator.this.columnHeaderMap.containsKey(this.artifact.getArtifactTypeID())) { + } else if (ReportGenerator.this.columnHeaderMap.containsKey(this.artifact.getArtifactTypeID())) { - for (Column currColumn : ReportGenerator.this.columnHeaderMap.get(this.artifact.getArtifactTypeID())) { - String cellData = currColumn.getCellData(this); - orderedRowData.add(cellData); - } + for (Column currColumn : ReportGenerator.this.columnHeaderMap.get(this.artifact.getArtifactTypeID())) { + String cellData = currColumn.getCellData(this); + orderedRowData.add(cellData); } } @@ -1976,7 +1939,8 @@ class ReportGenerator { private HashSet getUniqueTagNames(long artifactId) throws TskCoreException { HashSet uniqueTagNames = new HashSet<>(); - String query = "SELECT display_name, artifact_id FROM tag_names AS tn, blackboard_artifact_tags AS bat " + //NON-NLS + String query = "SELECT display_name, artifact_id FROM tag_names AS tn, blackboard_artifact_tags AS bat " + + //NON-NLS "WHERE tn.tag_name_id = bat.tag_name_id AND bat.artifact_id = " + artifactId; //NON-NLS try (CaseDbQuery dbQuery = skCase.executeQuery(query)) { diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel1.java b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel1.java index 7c2bc5193c..502c3162a3 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel1.java @@ -137,8 +137,8 @@ final class ReportVisualPanel1 extends JPanel implements ListSelectionListener { // Make sure that the report module has a valid non-null name. private boolean moduleIsValid(ReportModule module) { - return module.getName() != null && !module.getName().isEmpty() - && module.getRelativeFilePath() != null; + return module.getName() != null && !module.getName().isEmpty() + && module.getRelativeFilePath() != null; } private void popupWarning(ReportModule module) { @@ -163,13 +163,13 @@ final class ReportVisualPanel1 extends JPanel implements ListSelectionListener { * * @return */ - Map getTableModuleStates() { + TableReportModule getTableModule() { Map reportModuleStates = new LinkedHashMap<>(); ReportModule mod = getSelectedModule(); if (tableModules.contains(mod)) { - reportModuleStates.put((TableReportModule) mod, Boolean.TRUE); + return (TableReportModule) mod; } - return reportModuleStates; + return null; } /** @@ -177,13 +177,12 @@ final class ReportVisualPanel1 extends JPanel implements ListSelectionListener { * * @return */ - Map getGeneralModuleStates() { - Map reportModuleStates = new LinkedHashMap<>(); + GeneralReportModule getGeneralModule() { ReportModule mod = getSelectedModule(); if (generalModules.contains(mod)) { - reportModuleStates.put((GeneralReportModule) mod, Boolean.TRUE); + return (GeneralReportModule) mod; } - return reportModuleStates; + return null; } /** @@ -191,13 +190,12 @@ final class ReportVisualPanel1 extends JPanel implements ListSelectionListener { * * @return */ - Map getFileModuleStates() { - Map reportModuleStates = new LinkedHashMap<>(); + FileReportModule getFileModule() { ReportModule mod = getSelectedModule(); if (fileModules.contains(mod)) { - reportModuleStates.put((FileReportModule) mod, Boolean.TRUE); + return (FileReportModule) mod; } - return reportModuleStates; + return null; } /** diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java b/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java index bf51dfee86..0e350e12d1 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java @@ -65,9 +65,9 @@ public final class ReportWizardAction extends CallableSystemAction implements Pr wiz.setTitle(NbBundle.getMessage(ReportWizardAction.class, "ReportWizardAction.reportWiz.title")); if (DialogDisplayer.getDefault().notify(wiz) == WizardDescriptor.FINISH_OPTION) { @SuppressWarnings("unchecked") - ReportGenerator generator = new ReportGenerator((Map) wiz.getProperty("tableModuleStates"), //NON-NLS - (Map) wiz.getProperty("generalModuleStates"), //NON-NLS - (Map) wiz.getProperty("fileModuleStates")); //NON-NLS + ReportGenerator generator = new ReportGenerator((TableReportModule) wiz.getProperty("tableModule"), //NON-NLS + (GeneralReportModule) wiz.getProperty("generalModule"), //NON-NLS + (FileReportModule) wiz.getProperty("fileModule")); //NON-NLS generator.generateTableReports((Map) wiz.getProperty("artifactStates"), (Map) wiz.getProperty("tagStates")); //NON-NLS generator.generateFileListReports((Map) wiz.getProperty("fileReportOptions")); //NON-NLS generator.generateGeneralReports(); diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportWizardPanel1.java b/Core/src/org/sleuthkit/autopsy/report/ReportWizardPanel1.java index 9231a9685a..9677f7d6f5 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportWizardPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportWizardPanel1.java @@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.report; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Collection; -import java.util.Map; import java.util.prefs.Preferences; import javax.swing.JButton; import javax.swing.event.ChangeListener; @@ -108,17 +107,17 @@ class ReportWizardPanel1 implements WizardDescriptor.FinishablePanel tables = getComponent().getTableModuleStates(); - Map generals = getComponent().getGeneralModuleStates(); - wiz.putProperty("tableModuleStates", tables); //NON-NLS - wiz.putProperty("generalModuleStates", generals); //NON-NLS - wiz.putProperty("fileModuleStates", getComponent().getFileModuleStates()); //NON-NLS + TableReportModule module = getComponent().getTableModule(); + GeneralReportModule general = getComponent().getGeneralModule(); + wiz.putProperty("tableModule", module); //NON-NLS + wiz.putProperty("generalModule", general); //NON-NLS + wiz.putProperty("fileModule", getComponent().getFileModule()); //NON-NLS // Store preferences that WizardIterator will use to determine what // panels need to be shown Preferences prefs = NbPreferences.forModule(ReportWizardPanel1.class); - prefs.putBoolean("tableModule", any(tables.values())); //NON-NLS - prefs.putBoolean("generalModule", any(generals.values())); //NON-NLS + prefs.putBoolean("tableModuleState", module != null); //NON-NLS + prefs.putBoolean("generalModule", general != null); //NON-NLS } /** From c29f106d3eee2312bf8f7e8d85fff78c9e75e504 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Tue, 3 May 2016 10:21:28 -0400 Subject: [PATCH 002/172] Working towards a working cancellation policy. --- .../modules/stix/STIXReportModule.java | 48 ++-- .../autopsy/report/ReportGenerator.java | 219 +++++++----------- .../sleuthkit/autopsy/report/ReportKML.java | 25 +- .../autopsy/report/ReportVisualPanel1.java | 3 - 4 files changed, 129 insertions(+), 166 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java b/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java index 2762f21e26..ab42938cca 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java @@ -18,48 +18,45 @@ */ package org.sleuthkit.autopsy.modules.stix; -import java.io.File; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.List; -import java.util.logging.Level; import java.io.BufferedWriter; +import java.io.File; import java.io.FileWriter; +import java.io.IOException; import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; import javax.swing.JPanel; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; import javax.xml.namespace.QName; - import org.mitre.cybox.cybox_2.ObjectType; import org.mitre.cybox.cybox_2.Observable; import org.mitre.cybox.cybox_2.ObservableCompositionType; +import org.mitre.cybox.cybox_2.OperatorTypeEnum; +import org.mitre.cybox.objects.AccountObjectType; +import org.mitre.cybox.objects.Address; +import org.mitre.cybox.objects.DomainName; +import org.mitre.cybox.objects.EmailMessage; +import org.mitre.cybox.objects.FileObjectType; +import org.mitre.cybox.objects.SystemObjectType; +import org.mitre.cybox.objects.URIObjectType; +import org.mitre.cybox.objects.URLHistory; +import org.mitre.cybox.objects.WindowsNetworkShare; +import org.mitre.cybox.objects.WindowsRegistryKey; import org.mitre.stix.common_1.IndicatorBaseType; import org.mitre.stix.indicator_2.Indicator; import org.mitre.stix.stix_1.STIXPackage; - -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.report.GeneralReportModule; import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.report.ReportProgressPanel; -import org.sleuthkit.datamodel.TskCoreException; - -import org.mitre.cybox.cybox_2.OperatorTypeEnum; -import org.mitre.cybox.objects.Address; -import org.mitre.cybox.objects.FileObjectType; -import org.mitre.cybox.objects.URIObjectType; -import org.mitre.cybox.objects.EmailMessage; -import org.mitre.cybox.objects.WindowsNetworkShare; -import org.mitre.cybox.objects.AccountObjectType; -import org.mitre.cybox.objects.SystemObjectType; -import org.mitre.cybox.objects.URLHistory; -import org.mitre.cybox.objects.DomainName; -import org.mitre.cybox.objects.WindowsRegistryKey; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.ModuleSettings; +import org.sleuthkit.autopsy.report.GeneralReportModule; +import org.sleuthkit.autopsy.report.ReportProgressPanel; import org.sleuthkit.autopsy.report.ReportProgressPanel.ReportStatus; +import org.sleuthkit.datamodel.TskCoreException; /** * @@ -180,6 +177,9 @@ public class STIXReportModule implements GeneralReportModule { // Process each STIX file for (File file : stixFiles) { + if (progressPanel.getStatus() == ReportStatus.CANCELED) { + return; + } try { processFile(file.getAbsolutePath(), progressPanel); } catch (TskCoreException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java index c0c72447d6..7e4896b531 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java @@ -223,8 +223,10 @@ class ReportGenerator { * Run the GeneralReportModules using a SwingWorker. */ public void generateGeneralReports() { - GeneralReportsWorker worker = new GeneralReportsWorker(); - worker.execute(); + if (this.generalReportModule != null) { + GeneralReportsWorker worker = new GeneralReportsWorker(); + worker.execute(); + } } /** @@ -675,22 +677,21 @@ class ReportGenerator { // Tell the modules reporting on blackboard artifact tags data type is beginning. // @@@ Using the obsolete ARTIFACT_TYPE.TSK_TAG_ARTIFACT is an expedient hack. - progressPanel.updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", - ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getDisplayName())); - StringBuilder comment = new StringBuilder(); - if (!tagNamesFilter.isEmpty()) { - comment.append( - NbBundle.getMessage(this.getClass(), "ReportGenerator.makeBbArtTagTab.taggedRes.msg")); - comment.append(makeCommaSeparatedList(tagNamesFilter)); - } - module.startDataType(ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getDisplayName(), comment.toString()); - module.startTable(new ArrayList<>(Arrays.asList( - NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.resultType"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.tag"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.comment"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.srcFile")))); - + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", + ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getDisplayName())); + StringBuilder comment = new StringBuilder(); + if (!tagNamesFilter.isEmpty()) { + comment.append( + NbBundle.getMessage(this.getClass(), "ReportGenerator.makeBbArtTagTab.taggedRes.msg")); + comment.append(makeCommaSeparatedList(tagNamesFilter)); + } + tableReportModule.startDataType(ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getDisplayName(), comment.toString()); + tableReportModule.startTable(new ArrayList<>(Arrays.asList( + NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.resultType"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.tag"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.comment"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.srcFile")))); // Give the modules the rows for the content tags. for (BlackboardArtifactTag tag : tags) { @@ -699,21 +700,17 @@ class ReportGenerator { } List row; - for (TableReportModule module : tableModules) { - row = new ArrayList<>(Arrays.asList(tag.getArtifact().getArtifactTypeName(), tag.getName().getDisplayName(), tag.getComment(), tag.getContent().getName())); - module.addRow(row); - } + row = new ArrayList<>(Arrays.asList(tag.getArtifact().getArtifactTypeName(), tag.getName().getDisplayName(), tag.getComment(), tag.getContent().getName())); + tableReportModule.addRow(row); // check if the tag is an image that we should later make a thumbnail for checkIfTagHasImage(tag); } // The the modules blackboard artifact tags reporting is ended. - for (TableReportModule module : tableModules) { - tableProgress.get(module).increment(); - module.endTable(); - module.endDataType(); - } + progressPanel.increment(); + tableReportModule.endTable(); + tableReportModule.endDataType(); } /** @@ -728,35 +725,35 @@ class ReportGenerator { } void removeCancelledTableReportModules() { - if (progressPanel.getStatus() == ReportStatus.CANCELED) { - tableReportModule = null; - } + if (progressPanel.getStatus() == ReportStatus.CANCELED) { + tableReportModule = null; + } + } /** * Make a report for the files that were previously found to be images. */ private void makeThumbnailTable() { - for (TableReportModule module : tableModules) { - tableProgress.get(module).updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.createdThumb.text")); + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.createdThumb.text")); - if (module instanceof ReportHTML) { - ReportHTML htmlModule = (ReportHTML) module; - htmlModule.startDataType( - NbBundle.getMessage(this.getClass(), "ReportGenerator.thumbnailTable.name"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.thumbnailTable.desc")); - List emptyHeaders = new ArrayList<>(); - for (int i = 0; i < ReportHTML.THUMBNAIL_COLUMNS; i++) { - emptyHeaders.add(""); - } - htmlModule.startTable(emptyHeaders); - - htmlModule.addThumbnailRows(images); - - htmlModule.endTable(); - htmlModule.endDataType(); + if (tableReportModule instanceof ReportHTML) { + ReportHTML htmlModule = (ReportHTML) tableReportModule; + htmlModule.startDataType( + NbBundle.getMessage(this.getClass(), "ReportGenerator.thumbnailTable.name"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.thumbnailTable.desc")); + List emptyHeaders = new ArrayList<>(); + for (int i = 0; i < ReportHTML.THUMBNAIL_COLUMNS; i++) { + emptyHeaders.add(""); } + htmlModule.startTable(emptyHeaders); + + htmlModule.addThumbnailRows(images); + + htmlModule.endTable(); + htmlModule.endDataType(); } + } /** @@ -867,7 +864,7 @@ class ReportGenerator { * @param tableModules modules to report on */ @SuppressWarnings("deprecation") - private void writeKeywordHits(List tableModules, String comment, HashSet tagNamesFilter) { + private void writeKeywordHits(TableReportModule tableModule, String comment, HashSet tagNamesFilter) { // Query for keyword lists-only so that we can tell modules what lists // will exist for their index. @@ -905,13 +902,11 @@ class ReportGenerator { } // Make keyword data type and give them set index - for (TableReportModule module : tableModules) { - module.startDataType(ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName(), comment); - module.addSetIndex(lists); - tableProgress.get(module).updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", - ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName())); - } + tableModule.startDataType(ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName(), comment); + tableModule.addSetIndex(lists); + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", + ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName())); } catch (TskCoreException | SQLException ex) { errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedQueryKWLists")); logger.log(Level.SEVERE, "Failed to query keyword lists: ", ex); //NON-NLS @@ -958,16 +953,9 @@ class ReportGenerator { String currentList = ""; while (resultSet.next()) { // Check to see if all the TableReportModules have been canceled - if (tableModules.isEmpty()) { + if (progressPanel.getStatus() == ReportStatus.CANCELED) { break; } - Iterator iter = tableModules.iterator(); - while (iter.hasNext()) { - TableReportModule module = iter.next(); - if (tableProgress.get(module).getStatus() == ReportStatus.CANCELED) { - iter.remove(); - } - } // Get any tags that associated with this artifact and apply the tag filter. HashSet uniqueTagNames = getUniqueTagNames(resultSet.getLong("artifact_id")); //NON-NLS @@ -997,49 +985,37 @@ class ReportGenerator { if ((!list.equals(currentList) && !list.isEmpty()) || (list.isEmpty() && !currentList.equals( NbBundle.getMessage(this.getClass(), "ReportGenerator.writeKwHits.userSrchs")))) { if (!currentList.isEmpty()) { - for (TableReportModule module : tableModules) { - module.endTable(); - module.endSet(); - } + tableModule.endTable(); + tableModule.endSet(); } currentList = list.isEmpty() ? NbBundle .getMessage(this.getClass(), "ReportGenerator.writeKwHits.userSrchs") : list; currentKeyword = ""; // reset the current keyword because it's a new list - for (TableReportModule module : tableModules) { - module.startSet(currentList); - tableProgress.get(module).updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processingList", - ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName(), currentList)); - } + tableModule.startSet(currentList); + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processingList", + ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName(), currentList)); } if (!keyword.equals(currentKeyword)) { if (!currentKeyword.equals("")) { - for (TableReportModule module : tableModules) { - module.endTable(); - } + tableModule.endTable(); } currentKeyword = keyword; - for (TableReportModule module : tableModules) { - module.addSetElement(currentKeyword); - List columnHeaderNames = new ArrayList<>(); - columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.preview")); - columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")); - columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags")); - module.startTable(columnHeaderNames); - } + tableModule.addSetElement(currentKeyword); + List columnHeaderNames = new ArrayList<>(); + columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.preview")); + columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")); + columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags")); + tableModule.startTable(columnHeaderNames); } String previewreplace = EscapeUtil.escapeHtml(preview); - for (TableReportModule module : tableModules) { - module.addRow(Arrays.asList(new String[]{previewreplace.replaceAll(" tableModules, String comment, HashSet tagNamesFilter) { + private void writeHashsetHits(TableReportModule tableModule, String comment, HashSet tagNamesFilter) { String orderByClause; if (currentCase.getCaseType() == Case.CaseType.MULTI_USER_CASE) { orderByClause = "ORDER BY convert_to(att.value_text, 'SQL_ASCII') ASC NULLS FIRST"; //NON-NLS @@ -1080,13 +1056,11 @@ class ReportGenerator { lists.add(listsRs.getString("list")); //NON-NLS } - for (TableReportModule module : tableModules) { - module.startDataType(ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName(), comment); - module.addSetIndex(lists); - tableProgress.get(module).updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", - ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName())); - } + tableModule.startDataType(ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName(), comment); + tableModule.addSetIndex(lists); + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", + ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName())); } catch (TskCoreException | SQLException ex) { errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedQueryHashsetLists")); logger.log(Level.SEVERE, "Failed to query hashset lists: ", ex); //NON-NLS @@ -1122,16 +1096,9 @@ class ReportGenerator { String currentSet = ""; while (resultSet.next()) { // Check to see if all the TableReportModules have been canceled - if (tableModules.isEmpty()) { + if (progressPanel.getStatus() == ReportStatus.CANCELED) { break; } - Iterator iter = tableModules.iterator(); - while (iter.hasNext()) { - TableReportModule module = iter.next(); - if (tableProgress.get(module).getStatus() == ReportStatus.CANCELED) { - iter.remove(); - } - } // Get any tags that associated with this artifact and apply the tag filter. HashSet uniqueTagNames = getUniqueTagNames(resultSet.getLong("artifact_id")); //NON-NLS @@ -1160,36 +1127,28 @@ class ReportGenerator { // If the sets aren't the same, we've started a new set if (!set.equals(currentSet)) { if (!currentSet.isEmpty()) { - for (TableReportModule module : tableModules) { - module.endTable(); - module.endSet(); - } + tableModule.endTable(); + tableModule.endSet(); } currentSet = set; - for (TableReportModule module : tableModules) { - module.startSet(currentSet); - List columnHeaderNames = new ArrayList<>(); - columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.file")); - columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.size")); - columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags")); - module.startTable(columnHeaderNames); - tableProgress.get(module).updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processingList", - ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName(), currentSet)); - } + tableModule.startSet(currentSet); + List columnHeaderNames = new ArrayList<>(); + columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.file")); + columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.size")); + columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags")); + tableModule.startTable(columnHeaderNames); + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processingList", + ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName(), currentSet)); } // Add a row for this hit to every module - for (TableReportModule module : tableModules) { - module.addRow(Arrays.asList(new String[]{uniquePath, size, tagsList})); - } + tableModule.addRow(Arrays.asList(new String[]{uniquePath, size, tagsList})); } // Finish the current data type - for (TableReportModule module : tableModules) { - tableProgress.get(module).increment(); - module.endDataType(); - } + progressPanel.increment(); + tableModule.endDataType(); } catch (TskCoreException | SQLException ex) { errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedQueryHashsetHits")); logger.log(Level.SEVERE, "Failed to query hashsets hits: ", ex); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportKML.java b/Core/src/org/sleuthkit/autopsy/report/ReportKML.java index abdd7dee96..d8bb02508a 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportKML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportKML.java @@ -19,14 +19,6 @@ */ package org.sleuthkit.autopsy.report; -import javax.swing.JPanel; - -import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.datamodel.*; -import org.sleuthkit.autopsy.ingest.IngestManager; -import org.sleuthkit.datamodel.BlackboardArtifact; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; @@ -37,12 +29,18 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.logging.Level; +import javax.swing.JPanel; +import org.apache.commons.lang.StringEscapeUtils; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.Namespace; import org.jdom2.output.Format; import org.jdom2.output.XMLOutputter; -import org.apache.commons.lang.StringEscapeUtils; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.datamodel.*; /** * Generates a KML file based on geo coordinates store in blackboard. @@ -85,6 +83,9 @@ class ReportKML implements GeneralReportModule { currentCase = Case.getCurrentCase(); skCase = currentCase.getSleuthkitCase(); + if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) { + return; + } progressPanel.updateStatusLabel(NbBundle.getMessage(this.getClass(), "ReportKML.progress.loading")); // Check if ingest has finished String ingestwarning = ""; @@ -98,6 +99,9 @@ class ReportKML implements GeneralReportModule { // Why not just print the coordinates as we find them and make some utility methods to do the printing? // Should pull out time values for all of these points and store in TimeSpan element try { + if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) { + return; + } try (BufferedWriter out = new BufferedWriter(new FileWriter(reportPath2))) { double lat = 0; // temp latitude @@ -108,6 +112,9 @@ class ReportKML implements GeneralReportModule { File f; for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF)) { + if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) { + return; + } lat = 0; lon = 0; geoPath = ""; diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel1.java b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel1.java index 502c3162a3..93acae830a 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel1.java @@ -24,9 +24,7 @@ import java.util.ArrayList; import java.util.Collections; import static java.util.Collections.swap; import java.util.Comparator; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import java.util.logging.Level; import javax.swing.JList; import javax.swing.JPanel; @@ -164,7 +162,6 @@ final class ReportVisualPanel1 extends JPanel implements ListSelectionListener { * @return */ TableReportModule getTableModule() { - Map reportModuleStates = new LinkedHashMap<>(); ReportModule mod = getSelectedModule(); if (tableModules.contains(mod)) { return (TableReportModule) mod; From 25f954c4d361f00bfaf13ed1f1fae9a67380d71e Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Tue, 3 May 2016 12:01:17 -0400 Subject: [PATCH 003/172] Updated cancellation policy. --- .../autopsy/report/ReportGenerator.java | 58 +++++++------------ .../sleuthkit/autopsy/report/ReportKML.java | 7 --- 2 files changed, 22 insertions(+), 43 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java index 7e4896b531..6228a5b96d 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java @@ -318,7 +318,7 @@ class ReportGenerator { List files = getFiles(); int numFiles = files.size(); - if (fileReportModule != null) { + if (progressPanel.getStatus() != ReportStatus.CANCELED) { fileReportModule.startReport(reportPath); fileReportModule.startTable(enabledInfo); } @@ -329,12 +329,8 @@ class ReportGenerator { // Add files to report. for (AbstractFile file : files) { // Check to see if any reports have been cancelled. - if (fileReportModule == null) { - break; - } - // Remove cancelled reports, add files to report otherwise. if (progressPanel.getStatus() == ReportStatus.CANCELED) { - fileReportModule = null; + return 0; } else { fileReportModule.addRow(file, enabledInfo); progressPanel.increment(); @@ -428,22 +424,28 @@ class ReportGenerator { @Override protected Integer doInBackground() throws Exception { // Start the progress indicators for each active TableReportModule. - if (progressPanel.getStatus() == ReportStatus.CANCELED) { - } else { - tableReportModule.startReport(reportPath); - progressPanel.start(); - progressPanel.setIndeterminate(false); - progressPanel.setMaximumProgress(this.artifactTypes.size() + 2); // +2 for content and blackboard artifact tags - } + tableReportModule.startReport(reportPath); + progressPanel.start(); + progressPanel.setIndeterminate(false); + progressPanel.setMaximumProgress(this.artifactTypes.size() + 2); // +2 for content and blackboard artifact tags // report on the blackboard results - makeBlackboardArtifactTables(); + if (progressPanel.getStatus() != ReportStatus.CANCELED) { + makeBlackboardArtifactTables(); + } // report on the tagged files and artifacts - makeContentTagsTables(); - makeBlackboardArtifactTagsTables(); + if (progressPanel.getStatus() != ReportStatus.CANCELED) { + makeContentTagsTables(); + } - // report on the tagged images - makeThumbnailTable(); + if (progressPanel.getStatus() != ReportStatus.CANCELED) { + makeBlackboardArtifactTagsTables(); + } + + if (progressPanel.getStatus() != ReportStatus.CANCELED) { + // report on the tagged images + makeThumbnailTable(); + } // finish progress, wrap up progressPanel.complete(ReportStatus.COMPLETE); @@ -466,8 +468,8 @@ class ReportGenerator { // Add a table to the report for every enabled blackboard artifact type. for (BlackboardArtifact.Type type : artifactTypes) { // Check for cancellaton. - removeCancelledTableReportModules(); - if (tableReportModule == null) { + + if (progressPanel.getStatus() == ReportStatus.CANCELED) { return; } @@ -543,11 +545,6 @@ class ReportGenerator { */ @SuppressWarnings("deprecation") private void makeContentTagsTables() { - // Check for cancellaton. - removeCancelledTableReportModules(); - if (tableReportModule == null) { - return; - } // Get the content tags. List tags; @@ -660,11 +657,6 @@ class ReportGenerator { */ @SuppressWarnings("deprecation") private void makeBlackboardArtifactTagsTables() { - // Check for cancellaton. - removeCancelledTableReportModules(); - if (tableReportModule == null) { - return; - } List tags; try { @@ -724,12 +716,6 @@ class ReportGenerator { return tagNamesFilter.isEmpty() || tagNamesFilter.contains(tagName); } - void removeCancelledTableReportModules() { - if (progressPanel.getStatus() == ReportStatus.CANCELED) { - tableReportModule = null; - } - } - /** * Make a report for the files that were previously found to be images. */ diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportKML.java b/Core/src/org/sleuthkit/autopsy/report/ReportKML.java index d8bb02508a..f1542566fe 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportKML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportKML.java @@ -82,10 +82,6 @@ class ReportKML implements GeneralReportModule { String reportPath2 = baseReportDir + "ReportKML.txt"; //NON-NLS currentCase = Case.getCurrentCase(); skCase = currentCase.getSleuthkitCase(); - - if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) { - return; - } progressPanel.updateStatusLabel(NbBundle.getMessage(this.getClass(), "ReportKML.progress.loading")); // Check if ingest has finished String ingestwarning = ""; @@ -99,9 +95,6 @@ class ReportKML implements GeneralReportModule { // Why not just print the coordinates as we find them and make some utility methods to do the printing? // Should pull out time values for all of these points and store in TimeSpan element try { - if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) { - return; - } try (BufferedWriter out = new BufferedWriter(new FileWriter(reportPath2))) { double lat = 0; // temp latitude From 0e4717f1904cc24a1da62fb8fd3f1ced8cfcf849 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Tue, 3 May 2016 13:42:10 -0400 Subject: [PATCH 004/172] Added documentation. --- .../autopsy/report/ReportGenerator.java | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java index 6228a5b96d..4175831392 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java @@ -85,9 +85,16 @@ class ReportGenerator { private Case currentCase = Case.getCurrentCase(); private SleuthkitCase skCase = currentCase.getSleuthkitCase(); + /** + * Only one of the ReportModules below should be non-null for a given report + * generator. + */ private TableReportModule tableReportModule; private GeneralReportModule generalReportModule; private FileReportModule fileReportModule; + /** + * Progress panel that can be used to check for cancellation. + */ private ReportProgressPanel progressPanel; private Map> columnHeaderMap; @@ -101,8 +108,6 @@ class ReportGenerator { /** * Displays the list of errors during report generation in user-friendly * way. MessageNotifyUtil used to display bubble notification. - * - * @param listOfErrors List of strings explaining the errors. */ private void displayReportErrors() { if (!errorList.isEmpty()) { @@ -143,14 +148,14 @@ class ReportGenerator { * Create a ReportProgressPanel for each report generation module selected * by the user. * - * @param tableModule The enabled/disabled state of each - * TableReportModule - * @param generalModuleStates The enabled/disabled state of each - * GeneralReportModule - * @param fileListModuleStates The enabled/disabled state of each - * FileReportModule + * @param tableModule The TableReportModule + * @param generalModule The GeneralReportModule + * @param fileListModule The FileReportModule */ private void setupProgressPanels(TableReportModule tableModule, GeneralReportModule generalModule, FileReportModule fileListModule) { + /* + * Sets ups the progress panels based upon which one is null. + */ if (null != tableModule) { String reportFilePath = tableModule.getRelativeFilePath(); if (!reportFilePath.isEmpty()) { @@ -847,7 +852,7 @@ class ReportGenerator { /** * Write the keyword hits to the provided TableReportModules. * - * @param tableModules modules to report on + * @param tableModule module to report on */ @SuppressWarnings("deprecation") private void writeKeywordHits(TableReportModule tableModule, String comment, HashSet tagNamesFilter) { @@ -1011,7 +1016,7 @@ class ReportGenerator { /** * Write the hash set hits to the provided TableReportModules. * - * @param tableModules modules to report on + * @param tableModule module to report on */ @SuppressWarnings("deprecation") private void writeHashsetHits(TableReportModule tableModule, String comment, HashSet tagNamesFilter) { From f0b262b9aec2c27048cfdb7ea1ab2b8632e12489 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Tue, 3 May 2016 14:21:57 -0400 Subject: [PATCH 005/172] Updated documentation. --- .../sleuthkit/autopsy/report/ReportGenerator.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java index 4175831392..93e853ff92 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java @@ -121,7 +121,15 @@ class ReportGenerator { } } - ReportGenerator(TableReportModule tableModuleStates, GeneralReportModule generalModuleStates, FileReportModule fileListModuleStates) { + /** + * Creates a report generator. Only one of the passed arguments should be + * non-null. + * + * @param tableModule The table report module + * @param generalModule The general report module + * @param fileListModule The file report module + */ + ReportGenerator(TableReportModule tableModule, GeneralReportModule generalModule, FileReportModule fileListModule) { // Create the root reports directory path of the form: /Reports/ / DateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy-HH-mm-ss"); Date date = new Date(); @@ -140,7 +148,7 @@ class ReportGenerator { } // Initialize the progress panels - setupProgressPanels(tableModuleStates, generalModuleStates, fileListModuleStates); + setupProgressPanels(tableModule, generalModule, fileListModule); this.columnHeaderMap = new HashMap<>(); } From e060d843c4aac0cd831f7e2763a089d151c8eed5 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Tue, 3 May 2016 15:35:03 -0400 Subject: [PATCH 006/172] Fixed save configuration problem. --- Core/src/org/sleuthkit/autopsy/report/ReportWizardPanel1.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportWizardPanel1.java b/Core/src/org/sleuthkit/autopsy/report/ReportWizardPanel1.java index 9677f7d6f5..b5e3a80034 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportWizardPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportWizardPanel1.java @@ -116,7 +116,7 @@ class ReportWizardPanel1 implements WizardDescriptor.FinishablePanel Date: Tue, 10 May 2016 17:00:19 -0400 Subject: [PATCH 007/172] UTF-8 sanitize text before adding it to solr index --- .../sleuthkit/autopsy/coreutils/TextUtil.java | 22 +++++++++++++++++ .../keywordsearch/HtmlTextExtractor.java | 8 +++++++ .../keywordsearch/SolrSearchService.java | 9 ++++++- .../keywordsearch/TikaTextExtractor.java | 24 ++----------------- 4 files changed, 40 insertions(+), 23 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/TextUtil.java b/Core/src/org/sleuthkit/autopsy/coreutils/TextUtil.java index 053968d598..f2eed8e474 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/TextUtil.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/TextUtil.java @@ -57,4 +57,26 @@ public class TextUtil { return orientation; } + + + /** + * This method determines if a passed-in Java char (16 bits) is a valid + * UTF-8 printable character, returning true if so, false if not. + * + * Note that this method can have ramifications for characters outside the + * Unicode Base Multilingual Plane (BMP), which require more than 16 bits. + * We are using Java characters (16 bits) to look at the data and this will + * not accurately identify any non-BMP character (larger than 16 bits) + * ending with 0xFFFF and 0xFFFE. In the interest of a fast solution, we + * have chosen to ignore the extended planes above Unicode BMP for the time + * being. The net result of this is some non-BMP characters may be + * interspersed with '^' characters in Autopsy. + * + * @param ch the character to test + * + * @return Returns true if the character is valid UTF-8, false if not. + */ + public static boolean isValidSolrUTF8(char ch) { + return ((ch <= 0xFDD0 || ch >= 0xFDEF) && (ch > 0x1F || ch == 0x9 || ch == 0xA || ch == 0xD) && (ch != 0xFFFF) && (ch != 0xFFFE)); + } } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HtmlTextExtractor.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HtmlTextExtractor.java index 4e03038b39..cdbead3e7f 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HtmlTextExtractor.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HtmlTextExtractor.java @@ -28,6 +28,7 @@ import java.util.Map; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.StringExtract.StringExtractUnicodeTable.SCRIPT; +import org.sleuthkit.autopsy.coreutils.TextUtil; import org.sleuthkit.autopsy.keywordsearch.Ingester.IngesterException; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.ReadContentInputStream; @@ -162,6 +163,13 @@ class HtmlTextExtractor implements TextExtractor { } else { sb.append(textChunkBuf); } + + // Sanitize by replacing non-UTF-8 characters with caret '^' before adding to index + for (int i = 0; i < sb.length(); i++) { + if (!TextUtil.isValidSolrUTF8(sb.charAt(i))) { + sb.setCharAt(i, '^'); + } + } //reset for next chunk totalRead = 0; diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SolrSearchService.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SolrSearchService.java index 26c93f21e3..589ddc4fa2 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SolrSearchService.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SolrSearchService.java @@ -25,7 +25,6 @@ import org.apache.solr.client.solrj.impl.HttpSolrServer; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.keywordsearch.Ingester.IngesterException; import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService; import org.apache.solr.common.util.ContentStreamBase.StringStream; import org.openide.util.lookup.ServiceProvider; @@ -37,6 +36,7 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.openide.util.NbBundle; import java.net.InetAddress; import java.util.MissingResourceException; +import org.sleuthkit.autopsy.coreutils.TextUtil; import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchServiceException; /** @@ -156,6 +156,13 @@ public class SolrSearchService implements KeywordSearchService { documentId += "_" + Long.toString(chunkId); solrFields.replace(Server.Schema.ID.toString(), documentId); + + // Sanitize by replacing non-UTF-8 characters with caret '^' before adding to index + for (int i = 0; i < artifactContents.length(); i++) { + if (!TextUtil.isValidSolrUTF8(artifactContents.charAt(i))) { + artifactContents.setCharAt(i, '^'); + } + } StringStream contentStream = new StringStream(artifactContents.toString()); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TikaTextExtractor.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TikaTextExtractor.java index 3ccf669b58..7022fb1b8b 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TikaTextExtractor.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TikaTextExtractor.java @@ -32,6 +32,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; +import org.sleuthkit.autopsy.coreutils.TextUtil; import java.util.concurrent.TimeoutException; import java.util.logging.Level; @@ -188,7 +189,7 @@ class TikaTextExtractor implements TextExtractor { // Sanitize by replacing non-UTF-8 characters with caret '^' for (int i = 0; i < totalRead; ++i) { - if (!isValidSolrUTF8(textChunkBuf[i])) { + if (!TextUtil.isValidSolrUTF8(textChunkBuf[i])) { textChunkBuf[i] = '^'; } } @@ -255,27 +256,6 @@ class TikaTextExtractor implements TextExtractor { return success; } - /** - * This method determines if a passed-in Java char (16 bits) is a valid - * UTF-8 printable character, returning true if so, false if not. - * - * Note that this method can have ramifications for characters outside the - * Unicode Base Multilingual Plane (BMP), which require more than 16 bits. - * We are using Java characters (16 bits) to look at the data and this will - * not accurately identify any non-BMP character (larger than 16 bits) - * ending with 0xFFFF and 0xFFFE. In the interest of a fast solution, we - * have chosen to ignore the extended planes above Unicode BMP for the time - * being. The net result of this is some non-BMP characters may be - * interspersed with '^' characters in Autopsy. - * - * @param ch the character to test - * - * @return Returns true if the character is valid UTF-8, false if not. - */ - private static boolean isValidSolrUTF8(char ch) { - return ((ch <= 0xFDD0 || ch >= 0xFDEF) && (ch > 0x1F || ch == 0x9 || ch == 0xA || ch == 0xD) && (ch != 0xFFFF) && (ch != 0xFFFE)); - } - @Override public boolean isContentTypeSpecific() { return true; From a09cbfca87d580ed06a95b5e0bc5342785072caf Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Wed, 11 May 2016 10:08:16 -0400 Subject: [PATCH 008/172] Used anonymous swing workers to generate reports, finished cleanup. --- .../autopsy/report/ReportGenerator.java | 2002 ++--------------- .../autopsy/report/ReportWizardAction.java | 16 +- .../autopsy/report/TableReportGenerator.java | 1680 ++++++++++++++ 3 files changed, 1849 insertions(+), 1849 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java index 93e853ff92..fd33d20c7a 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java @@ -26,24 +26,14 @@ import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; import java.io.IOException; -import java.sql.ResultSet; -import java.sql.SQLException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.Objects; -import java.util.Set; -import java.util.TreeSet; import java.util.concurrent.ExecutionException; import java.util.logging.Level; import javax.swing.JDialog; @@ -52,29 +42,18 @@ import javax.swing.SwingWorker; import org.openide.filesystems.FileUtil; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.coreutils.EscapeUtil; -import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; -import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.autopsy.report.ReportProgressPanel.ReportStatus; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; -import org.sleuthkit.datamodel.BlackboardArtifactTag; -import org.sleuthkit.datamodel.BlackboardAttribute; -import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; -import org.sleuthkit.datamodel.BlackboardAttribute.Type; -import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.SleuthkitCase; -import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; /** * Instances of this class use GeneralReportModules, TableReportModules and - * FileReportModules to generate a report. If desired, displayProgressPanels() + * FileReportModules to generate a report. If desired, displayProgressPanel() * can be called to show report generation progress using ReportProgressPanel * objects displayed using a dialog box. */ @@ -96,7 +75,6 @@ class ReportGenerator { * Progress panel that can be used to check for cancellation. */ private ReportProgressPanel progressPanel; - private Map> columnHeaderMap; private String reportPath; private ReportGenerationPanel panel = new ReportGenerationPanel(); @@ -117,7 +95,6 @@ class ReportGenerator { } MessageNotifyUtil.Notify.error( NbBundle.getMessage(this.getClass(), "ReportGenerator.notifyErr.errsDuringRptGen"), errorString); - return; } } @@ -125,8 +102,8 @@ class ReportGenerator { * Creates a report generator. Only one of the passed arguments should be * non-null. * - * @param tableModule The table report module - * @param generalModule The general report module + * @param tableModule The table report module + * @param generalModule The general report module * @param fileListModule The file report module */ ReportGenerator(TableReportModule tableModule, GeneralReportModule generalModule, FileReportModule fileListModule) { @@ -148,61 +125,13 @@ class ReportGenerator { } // Initialize the progress panels - setupProgressPanels(tableModule, generalModule, fileListModule); - this.columnHeaderMap = new HashMap<>(); - } - - /** - * Create a ReportProgressPanel for each report generation module selected - * by the user. - * - * @param tableModule The TableReportModule - * @param generalModule The GeneralReportModule - * @param fileListModule The FileReportModule - */ - private void setupProgressPanels(TableReportModule tableModule, GeneralReportModule generalModule, FileReportModule fileListModule) { - /* - * Sets ups the progress panels based upon which one is null. - */ - if (null != tableModule) { - String reportFilePath = tableModule.getRelativeFilePath(); - if (!reportFilePath.isEmpty()) { - this.tableReportModule = tableModule; - this.progressPanel = panel.addReport(tableModule.getName(), reportPath + reportFilePath); - } else { - this.tableReportModule = tableModule; - this.progressPanel = panel.addReport(tableModule.getName(), null); - } - } - - if (null != generalModule) { - String reportFilePath = generalModule.getRelativeFilePath(); - if (!reportFilePath.isEmpty()) { - this.generalReportModule = generalModule; - this.progressPanel = panel.addReport(generalModule.getName(), reportPath + reportFilePath); - } else { - this.generalReportModule = generalModule; - this.progressPanel = panel.addReport(generalModule.getName(), null); - } - } - - if (null != fileListModule) { - String reportFilePath = fileListModule.getRelativeFilePath(); - if (!reportFilePath.isEmpty()) { - fileReportModule = fileListModule; - this.progressPanel = panel.addReport(fileListModule.getName(), reportPath + reportFilePath); - } else { - fileReportModule = fileListModule; - this.progressPanel = panel.addReport(fileListModule.getName(), null); - } - } } /** * Display the progress panels to the user, and add actions to close the * parent dialog. */ - public void displayProgressPanels() { + public void displayProgressPanel() { final JDialog dialog = new JDialog(new JFrame(), true); dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); dialog.setTitle(NbBundle.getMessage(this.getClass(), "ReportGenerator.displayProgress.title.text")); @@ -235,10 +164,41 @@ class ReportGenerator { /** * Run the GeneralReportModules using a SwingWorker. */ - public void generateGeneralReports() { - if (this.generalReportModule != null) { - GeneralReportsWorker worker = new GeneralReportsWorker(); + void generateGeneralReport(GeneralReportModule generalReportModule) { + if (generalReportModule != null) { + String reportFilePath = generalReportModule.getRelativeFilePath(); + if (!reportFilePath.isEmpty()) { + this.progressPanel = panel.addReport(generalReportModule.getName(), reportPath + reportFilePath); + } else { + this.progressPanel = panel.addReport(generalReportModule.getName(), null); + } + SwingWorker worker = new SwingWorker() { + @Override + protected Integer doInBackground() throws Exception { + generalReportModule.generateReport(reportPath, progressPanel); + return 1; + } + + @Override + protected void done() { + try { + get(); + } catch (InterruptedException | ExecutionException ex) { + MessageNotifyUtil.Notify.show( + NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorTitle"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorText") + ex.getLocalizedMessage(), + MessageNotifyUtil.MessageType.ERROR); + logger.log(Level.SEVERE, "failed to generate reports", ex); //NON-NLS + } // catch and ignore if we were cancelled + catch (java.util.concurrent.CancellationException ex) { + } finally { + displayReportErrors(); + errorList.clear(); + } + } + }; worker.execute(); + displayProgressPanel(); } } @@ -250,10 +210,45 @@ class ReportGenerator { * @param tagSelections the enabled/disabled state of the tag names * to be included in the report */ - public void generateTableReports(Map artifactTypeSelections, Map tagNameSelections) { - if (tableReportModule != null && null != artifactTypeSelections) { - TableReportsWorker worker = new TableReportsWorker(artifactTypeSelections, tagNameSelections); + void generateTableReport(TableReportModule tableReport, Map artifactTypeSelections, Map tagNameSelections) { + if (tableReport != null && null != artifactTypeSelections) { + String reportFilePath = tableReport.getRelativeFilePath(); + if (!reportFilePath.isEmpty()) { + this.progressPanel = panel.addReport(tableReport.getName(), reportPath + reportFilePath); + } else { + this.progressPanel = panel.addReport(tableReport.getName(), null); + } + SwingWorker worker = new SwingWorker() { + @Override + protected Integer doInBackground() throws Exception { + tableReport.startReport(reportPath); + TableReportGenerator generator = new TableReportGenerator(artifactTypeSelections, tagNameSelections, progressPanel, tableReport); + generator.execute(); + tableReport.endReport(); + errorList = generator.getErrorList(); + return 1; + } + + @Override + protected void done() { + try { + get(); + } catch (InterruptedException | ExecutionException ex) { + MessageNotifyUtil.Notify.show( + NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorTitle"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorText") + ex.getLocalizedMessage(), + MessageNotifyUtil.MessageType.ERROR); + logger.log(Level.SEVERE, "failed to generate reports", ex); //NON-NLS + } // catch and ignore if we were cancelled + catch (java.util.concurrent.CancellationException ex) { + } finally { + displayReportErrors(); + errorList.clear(); + } + } + }; worker.execute(); + displayProgressPanel(); } } @@ -263,7 +258,7 @@ class ReportGenerator { * @param enabledInfo the Information that should be included about each * file in the report. */ - public void generateFileListReports(Map enabledInfo) { + void generateFileListReport(FileReportModule fileReportModule, Map enabledInfo) { if (fileReportModule != null && null != enabledInfo) { List enabled = new ArrayList<>(); for (Entry e : enabledInfo.entrySet()) { @@ -271,1777 +266,96 @@ class ReportGenerator { enabled.add(e.getKey()); } } - FileReportsWorker worker = new FileReportsWorker(enabled); + String reportFilePath = fileReportModule.getRelativeFilePath(); + if (!reportFilePath.isEmpty()) { + this.progressPanel = panel.addReport(fileReportModule.getName(), reportPath + reportFilePath); + } else { + this.progressPanel = panel.addReport(fileReportModule.getName(), null); + } + SwingWorker worker = new SwingWorker() { + @Override + protected Integer doInBackground() throws Exception { + if (progressPanel.getStatus() != ReportStatus.CANCELED) { + progressPanel.start(); + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.queryingDb.text")); + } + + List files = getFiles(); + int numFiles = files.size(); + if (progressPanel.getStatus() != ReportStatus.CANCELED) { + fileReportModule.startReport(reportPath); + fileReportModule.startTable(enabled); + } + progressPanel.setIndeterminate(false); + progressPanel.setMaximumProgress(numFiles); + + int i = 0; + // Add files to report. + for (AbstractFile file : files) { + // Check to see if any reports have been cancelled. + if (progressPanel.getStatus() == ReportStatus.CANCELED) { + return 0; + } else { + fileReportModule.addRow(file, enabled); + progressPanel.increment(); + } + + if ((i % 100) == 0) { + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processingFile.text", + file.getName())); + } + i++; + } + + fileReportModule.endTable(); + fileReportModule.endReport(); + progressPanel.complete(ReportStatus.COMPLETE); + return 1; + } + + @Override + protected void done() { + try { + get(); + } catch (InterruptedException | ExecutionException ex) { + MessageNotifyUtil.Notify.show( + NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorTitle"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorText") + ex.getLocalizedMessage(), + MessageNotifyUtil.MessageType.ERROR); + logger.log(Level.SEVERE, "failed to generate reports", ex); //NON-NLS + } // catch and ignore if we were cancelled + catch (java.util.concurrent.CancellationException ex) { + } finally { + displayReportErrors(); + errorList.clear(); + } + } + }; worker.execute(); - + displayProgressPanel(); } } /** - * SwingWorker to run GeneralReportModules. - */ - private class GeneralReportsWorker extends SwingWorker { - - @Override - protected Integer doInBackground() throws Exception { - if (progressPanel.getStatus() != ReportStatus.CANCELED) { - generalReportModule.generateReport(reportPath, progressPanel); - } - return 0; - } - - @Override - protected void done() { - try { - get(); - } catch (InterruptedException | ExecutionException ex) { - MessageNotifyUtil.Notify.show( - NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorTitle"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorText") + ex.getLocalizedMessage(), - MessageNotifyUtil.MessageType.ERROR); - logger.log(Level.SEVERE, "failed to generate reports", ex); //NON-NLS - } // catch and ignore if we were cancelled - catch (java.util.concurrent.CancellationException ex) { - } finally { - displayReportErrors(); - errorList.clear(); - } - } - - } - - /** - * SwingWorker to run FileReportModules. - */ - private class FileReportsWorker extends SwingWorker { - - private List enabledInfo = Arrays.asList(FileReportDataTypes.values()); - - FileReportsWorker(List enabled) { - enabledInfo = enabled; - } - - @Override - protected Integer doInBackground() throws Exception { - if (progressPanel.getStatus() != ReportStatus.CANCELED) { - progressPanel.start(); - progressPanel.updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.queryingDb.text")); - } - - List files = getFiles(); - int numFiles = files.size(); - if (progressPanel.getStatus() != ReportStatus.CANCELED) { - fileReportModule.startReport(reportPath); - fileReportModule.startTable(enabledInfo); - } - progressPanel.setIndeterminate(false); - progressPanel.setMaximumProgress(numFiles); - - int i = 0; - // Add files to report. - for (AbstractFile file : files) { - // Check to see if any reports have been cancelled. - if (progressPanel.getStatus() == ReportStatus.CANCELED) { - return 0; - } else { - fileReportModule.addRow(file, enabledInfo); - progressPanel.increment(); - } - - if ((i % 100) == 0) { - progressPanel.updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processingFile.text", - file.getName())); - } - i++; - } - - fileReportModule.endTable(); - fileReportModule.endReport(); - progressPanel.complete(ReportStatus.COMPLETE); - - return 0; - } - - /** - * Get all files in the image. - * - * @return - */ - private List getFiles() { - List absFiles; - try { - SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase(); - absFiles = skCase.findAllFilesWhere("meta_type != " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()); //NON-NLS - return absFiles; - } catch (TskCoreException ex) { - MessageNotifyUtil.Notify.show( - NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorTitle"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorText") + ex.getLocalizedMessage(), - MessageNotifyUtil.MessageType.ERROR); - logger.log(Level.SEVERE, "failed to generate reports. Unable to get all files in the image.", ex); //NON-NLS - return Collections.emptyList(); - } - } - - @Override - protected void done() { - try { - get(); - } catch (InterruptedException | ExecutionException ex) { - MessageNotifyUtil.Notify.show( - NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorTitle"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorText") + ex.getLocalizedMessage(), - MessageNotifyUtil.MessageType.ERROR); - logger.log(Level.SEVERE, "failed to generate reports", ex); //NON-NLS - } // catch and ignore if we were cancelled - catch (java.util.concurrent.CancellationException ex) { - } finally { - displayReportErrors(); - errorList.clear(); - } - } - } - - /** - * SwingWorker to run TableReportModules to report on blackboard artifacts, - * content tags, and blackboard artifact tags. - */ - private class TableReportsWorker extends SwingWorker { - - private List artifactTypes = new ArrayList<>(); - private HashSet tagNamesFilter = new HashSet<>(); - - private List images = new ArrayList<>(); - - TableReportsWorker(Map artifactTypeSelections, Map tagNameSelections) { - - // Get the artifact types selected by the user. - for (Entry entry : artifactTypeSelections.entrySet()) { - if (entry.getValue()) { - artifactTypes.add(entry.getKey()); - } - } - - // Get the tag names selected by the user and make a tag names filter. - if (null != tagNameSelections) { - for (Entry entry : tagNameSelections.entrySet()) { - if (entry.getValue() == true) { - tagNamesFilter.add(entry.getKey()); - } - } - } - } - - @Override - protected Integer doInBackground() throws Exception { - // Start the progress indicators for each active TableReportModule. - tableReportModule.startReport(reportPath); - progressPanel.start(); - progressPanel.setIndeterminate(false); - progressPanel.setMaximumProgress(this.artifactTypes.size() + 2); // +2 for content and blackboard artifact tags - // report on the blackboard results - if (progressPanel.getStatus() != ReportStatus.CANCELED) { - makeBlackboardArtifactTables(); - } - - // report on the tagged files and artifacts - if (progressPanel.getStatus() != ReportStatus.CANCELED) { - makeContentTagsTables(); - } - - if (progressPanel.getStatus() != ReportStatus.CANCELED) { - makeBlackboardArtifactTagsTables(); - } - - if (progressPanel.getStatus() != ReportStatus.CANCELED) { - // report on the tagged images - makeThumbnailTable(); - } - - // finish progress, wrap up - progressPanel.complete(ReportStatus.COMPLETE); - tableReportModule.endReport(); - - return 0; - } - - /** - * Generate the tables for the selected blackboard artifacts - */ - private void makeBlackboardArtifactTables() { - // Make a comment string describing the tag names filter in effect. - StringBuilder comment = new StringBuilder(); - if (!tagNamesFilter.isEmpty()) { - comment.append(NbBundle.getMessage(this.getClass(), "ReportGenerator.artifactTable.taggedResults.text")); - comment.append(makeCommaSeparatedList(tagNamesFilter)); - } - - // Add a table to the report for every enabled blackboard artifact type. - for (BlackboardArtifact.Type type : artifactTypes) { - // Check for cancellaton. - - if (progressPanel.getStatus() == ReportStatus.CANCELED) { - return; - } - - progressPanel.updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", - type.getDisplayName())); - - // Keyword hits and hashset hit artifacts get special handling. - if (type.getTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { - writeKeywordHits(tableReportModule, comment.toString(), tagNamesFilter); - continue; - } else if (type.getTypeID() == ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) { - writeHashsetHits(tableReportModule, comment.toString(), tagNamesFilter); - continue; - } - - List artifactList = getFilteredArtifacts(type, tagNamesFilter); - - if (artifactList.isEmpty()) { - continue; - } - - /* - Gets all of the attribute types of this artifact type by adding - all of the types to a set - */ - Set attrTypeSet = new TreeSet<>((Type o1, Type o2) -> o1.getDisplayName().compareTo(o2.getDisplayName())); - for (ArtifactData data : artifactList) { - List attributes = data.getAttributes(); - for (BlackboardAttribute attribute : attributes) { - attrTypeSet.add(attribute.getAttributeType()); - } - } - // Get the columns appropriate for the artifact type. This is - // used to get the data that will be in the cells below based on - // type, and display the column headers. - List columns = getArtifactTableColumns(type.getTypeID(), attrTypeSet); - if (columns.isEmpty()) { - continue; - } - ReportGenerator.this.columnHeaderMap.put(type.getTypeID(), columns); - - // The artifact list is sorted now, as getting the row data is - // dependent on having the columns, which is necessary for - // sorting. - Collections.sort(artifactList); - List columnHeaderNames = new ArrayList<>(); - for (Column currColumn : columns) { - columnHeaderNames.add(currColumn.getColumnHeader()); - } - - tableReportModule.startDataType(type.getDisplayName(), comment.toString()); - tableReportModule.startTable(columnHeaderNames); - for (ArtifactData artifactData : artifactList) { - // Get the row data for this artifact, and has the - // module add it. - List rowData = artifactData.getRow(); - if (rowData.isEmpty()) { - continue; - } - - tableReportModule.addRow(rowData); - } - // Finish up this data type - progressPanel.increment(); - tableReportModule.endTable(); - tableReportModule.endDataType(); - } - } - - /** - * Make table for tagged files - */ - @SuppressWarnings("deprecation") - private void makeContentTagsTables() { - - // Get the content tags. - List tags; - try { - tags = Case.getCurrentCase().getServices().getTagsManager().getAllContentTags(); - } catch (TskCoreException ex) { - errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetContentTags")); - logger.log(Level.SEVERE, "failed to get content tags", ex); //NON-NLS - return; - } - - // Tell the modules reporting on content tags is beginning. - // @@@ This casting is a tricky little workaround to allow the HTML report module to slip in a content hyperlink. - // @@@ Alos Using the obsolete ARTIFACT_TYPE.TSK_TAG_FILE is also an expedient hack. - progressPanel.updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", - ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName())); - ArrayList columnHeaders = new ArrayList<>(Arrays.asList( - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.tag"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.file"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.comment"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeModified"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeChanged"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeAccessed"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeCreated"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.size"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.hash"))); - - StringBuilder comment = new StringBuilder(); - if (!tagNamesFilter.isEmpty()) { - comment.append( - NbBundle.getMessage(this.getClass(), "ReportGenerator.makeContTagTab.taggedFiles.msg")); - comment.append(makeCommaSeparatedList(tagNamesFilter)); - } - if (tableReportModule instanceof ReportHTML) { - ReportHTML htmlReportModule = (ReportHTML) tableReportModule; - htmlReportModule.startDataType(ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName(), comment.toString()); - htmlReportModule.startContentTagsTable(columnHeaders); - } else { - tableReportModule.startDataType(ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName(), comment.toString()); - tableReportModule.startTable(columnHeaders); - } - - // Give the modules the rows for the content tags. - for (ContentTag tag : tags) { - // skip tags that we are not reporting on - if (passesTagNamesFilter(tag.getName().getDisplayName()) == false) { - continue; - } - - String fileName; - try { - fileName = tag.getContent().getUniquePath(); - } catch (TskCoreException ex) { - fileName = tag.getContent().getName(); - } - - ArrayList rowData = new ArrayList<>(Arrays.asList(tag.getName().getDisplayName(), fileName, tag.getComment())); - Content content = tag.getContent(); - if (content instanceof AbstractFile) { - AbstractFile file = (AbstractFile) content; - - // Add metadata about the file to HTML output - rowData.add(file.getMtimeAsDate()); - rowData.add(file.getCtimeAsDate()); - rowData.add(file.getAtimeAsDate()); - rowData.add(file.getCrtimeAsDate()); - rowData.add(Long.toString(file.getSize())); - rowData.add(file.getMd5Hash()); - } - // @@@ This casting is a tricky little workaround to allow the HTML report module to slip in a content hyperlink. - if (tableReportModule instanceof ReportHTML) { - ReportHTML htmlReportModule = (ReportHTML) tableReportModule; - htmlReportModule.addRowWithTaggedContentHyperlink(rowData, tag); - } else { - tableReportModule.addRow(rowData); - } - - // see if it is for an image so that we later report on it - checkIfTagHasImage(tag); - } - - // The the modules content tags reporting is ended. - progressPanel.increment(); - tableReportModule.endTable(); - tableReportModule.endDataType(); - } - - @Override - protected void done() { - try { - get(); - } catch (InterruptedException | ExecutionException ex) { - MessageNotifyUtil.Notify.show( - NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorTitle"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorText") + ex.getLocalizedMessage(), - MessageNotifyUtil.MessageType.ERROR); - logger.log(Level.SEVERE, "failed to generate reports", ex.getCause()); //NON-NLS - logger.log(Level.SEVERE, "failed to generate reports", ex); //NON-NLS - } // catch and ignore if we were cancelled - catch (java.util.concurrent.CancellationException ex) { - } finally { - displayReportErrors(); - errorList.clear(); - } - } - - /** - * Generate the tables for the tagged artifacts - */ - @SuppressWarnings("deprecation") - private void makeBlackboardArtifactTagsTables() { - - List tags; - try { - tags = Case.getCurrentCase().getServices().getTagsManager().getAllBlackboardArtifactTags(); - } catch (TskCoreException ex) { - errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetBBArtifactTags")); - logger.log(Level.SEVERE, "failed to get blackboard artifact tags", ex); //NON-NLS - return; - } - - // Tell the modules reporting on blackboard artifact tags data type is beginning. - // @@@ Using the obsolete ARTIFACT_TYPE.TSK_TAG_ARTIFACT is an expedient hack. - progressPanel.updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", - ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getDisplayName())); - StringBuilder comment = new StringBuilder(); - if (!tagNamesFilter.isEmpty()) { - comment.append( - NbBundle.getMessage(this.getClass(), "ReportGenerator.makeBbArtTagTab.taggedRes.msg")); - comment.append(makeCommaSeparatedList(tagNamesFilter)); - } - tableReportModule.startDataType(ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getDisplayName(), comment.toString()); - tableReportModule.startTable(new ArrayList<>(Arrays.asList( - NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.resultType"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.tag"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.comment"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.srcFile")))); - - // Give the modules the rows for the content tags. - for (BlackboardArtifactTag tag : tags) { - if (passesTagNamesFilter(tag.getName().getDisplayName()) == false) { - continue; - } - - List row; - row = new ArrayList<>(Arrays.asList(tag.getArtifact().getArtifactTypeName(), tag.getName().getDisplayName(), tag.getComment(), tag.getContent().getName())); - tableReportModule.addRow(row); - - // check if the tag is an image that we should later make a thumbnail for - checkIfTagHasImage(tag); - } - - // The the modules blackboard artifact tags reporting is ended. - progressPanel.increment(); - tableReportModule.endTable(); - tableReportModule.endDataType(); - } - - /** - * Test if the user requested that this tag be reported on - * - * @param tagName - * - * @return true if it should be reported on - */ - private boolean passesTagNamesFilter(String tagName) { - return tagNamesFilter.isEmpty() || tagNamesFilter.contains(tagName); - } - - /** - * Make a report for the files that were previously found to be images. - */ - private void makeThumbnailTable() { - progressPanel.updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.createdThumb.text")); - - if (tableReportModule instanceof ReportHTML) { - ReportHTML htmlModule = (ReportHTML) tableReportModule; - htmlModule.startDataType( - NbBundle.getMessage(this.getClass(), "ReportGenerator.thumbnailTable.name"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.thumbnailTable.desc")); - List emptyHeaders = new ArrayList<>(); - for (int i = 0; i < ReportHTML.THUMBNAIL_COLUMNS; i++) { - emptyHeaders.add(""); - } - htmlModule.startTable(emptyHeaders); - - htmlModule.addThumbnailRows(images); - - htmlModule.endTable(); - htmlModule.endDataType(); - } - - } - - /** - * Analyze artifact associated with tag and add to internal list if it - * is associated with an image. - * - * @param artifactTag - */ - private void checkIfTagHasImage(BlackboardArtifactTag artifactTag) { - AbstractFile file; - try { - file = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(artifactTag.getArtifact().getObjectID()); - } catch (TskCoreException ex) { - errorList.add( - NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.errGetContentFromBBArtifact")); - logger.log(Level.WARNING, "Error while getting content from a blackboard artifact to report on.", ex); //NON-NLS - return; - } - - if (file != null) { - checkIfFileIsImage(file); - } - } - - /** - * Analyze file that tag is associated with and determine if it is an - * image and should have a thumbnail reported for it. Images are added - * to internal list. - * - * @param contentTag - */ - private void checkIfTagHasImage(ContentTag contentTag) { - Content c = contentTag.getContent(); - if (c instanceof AbstractFile == false) { - return; - } - checkIfFileIsImage((AbstractFile) c); - } - - /** - * If file is an image file, add it to the internal 'images' list. - * - * @param file - */ - private void checkIfFileIsImage(AbstractFile file) { - - if (file.isDir() - || file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS - || file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) { - return; - } - - if (ImageUtils.thumbnailSupported(file)) { - images.add(file); - } - } - } - -/// @@@ Should move the methods specific to TableReportsWorker into that scope. - private Boolean failsTagFilter(HashSet tagNames, HashSet tagsNamesFilter) { - if (null == tagsNamesFilter || tagsNamesFilter.isEmpty()) { - return false; - } - - HashSet filteredTagNames = new HashSet<>(tagNames); - filteredTagNames.retainAll(tagsNamesFilter); - return filteredTagNames.isEmpty(); - } - - /** - * Get a List of the artifacts and data of the given type that pass the - * given Tag Filter. + * Get all files in the image. * - * @param type The artifact type to get - * @param tagNamesFilter The tag names that should be included. - * - * @return a list of the filtered tags. + * @return */ - private List getFilteredArtifacts(BlackboardArtifact.Type type, HashSet tagNamesFilter) { - List artifacts = new ArrayList<>(); + private List getFiles() { + List absFiles; try { - for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(type.getTypeID())) { - List tags = Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact); - HashSet uniqueTagNames = new HashSet<>(); - for (BlackboardArtifactTag tag : tags) { - uniqueTagNames.add(tag.getName().getDisplayName()); - } - if (failsTagFilter(uniqueTagNames, tagNamesFilter)) { - continue; - } - try { - artifacts.add(new ArtifactData(artifact, skCase.getBlackboardAttributes(artifact), uniqueTagNames)); - } catch (TskCoreException ex) { - errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetBBAttribs")); - logger.log(Level.SEVERE, "Failed to get Blackboard Attributes when generating report.", ex); //NON-NLS - } - } + SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase(); + absFiles = skCase.findAllFilesWhere("meta_type != " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()); //NON-NLS + return absFiles; } catch (TskCoreException ex) { - errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetBBArtifacts")); - logger.log(Level.SEVERE, "Failed to get Blackboard Artifacts when generating report.", ex); //NON-NLS - } - return artifacts; - } - - /** - * Write the keyword hits to the provided TableReportModules. - * - * @param tableModule module to report on - */ - @SuppressWarnings("deprecation") - private void writeKeywordHits(TableReportModule tableModule, String comment, HashSet tagNamesFilter) { - - // Query for keyword lists-only so that we can tell modules what lists - // will exist for their index. - // @@@ There is a bug in here. We should use the tags in the below code - // so that we only report the lists that we will later provide with real - // hits. If no keyord hits are tagged, then we make the page for nothing. - String orderByClause; - if (currentCase.getCaseType() == Case.CaseType.MULTI_USER_CASE) { - orderByClause = "ORDER BY convert_to(att.value_text, 'SQL_ASCII') ASC NULLS FIRST"; //NON-NLS - } else { - orderByClause = "ORDER BY list ASC"; //NON-NLS - } - String keywordListQuery - = "SELECT att.value_text AS list " - + //NON-NLS - "FROM blackboard_attributes AS att, blackboard_artifacts AS art " - + //NON-NLS - "WHERE att.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + " " - + //NON-NLS - "AND art.artifact_type_id = " + ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + " " - + //NON-NLS - "AND att.artifact_id = art.artifact_id " - + //NON-NLS - "GROUP BY list " + orderByClause; //NON-NLS - - try (CaseDbQuery dbQuery = skCase.executeQuery(keywordListQuery)) { - ResultSet listsRs = dbQuery.getResultSet(); - List lists = new ArrayList<>(); - while (listsRs.next()) { - String list = listsRs.getString("list"); //NON-NLS - if (list.isEmpty()) { - list = NbBundle.getMessage(this.getClass(), "ReportGenerator.writeKwHits.userSrchs"); - } - lists.add(list); - } - - // Make keyword data type and give them set index - tableModule.startDataType(ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName(), comment); - tableModule.addSetIndex(lists); - progressPanel.updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", - ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName())); - } catch (TskCoreException | SQLException ex) { - errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedQueryKWLists")); - logger.log(Level.SEVERE, "Failed to query keyword lists: ", ex); //NON-NLS - return; - } - - if (currentCase.getCaseType() == Case.CaseType.MULTI_USER_CASE) { - orderByClause = "ORDER BY convert_to(att3.value_text, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS - + "convert_to(att1.value_text, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS - + "convert_to(f.parent_path, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS - + "convert_to(f.name, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS - + "convert_to(att2.value_text, 'SQL_ASCII') ASC NULLS FIRST"; //NON-NLS - } else { - orderByClause = "ORDER BY list ASC, keyword ASC, parent_path ASC, name ASC, preview ASC"; //NON-NLS - } - // Query for keywords, grouped by list - String keywordsQuery - = "SELECT art.artifact_id, art.obj_id, att1.value_text AS keyword, att2.value_text AS preview, att3.value_text AS list, f.name AS name, f.parent_path AS parent_path " - + //NON-NLS - "FROM blackboard_artifacts AS art, blackboard_attributes AS att1, blackboard_attributes AS att2, blackboard_attributes AS att3, tsk_files AS f " - + //NON-NLS - "WHERE (att1.artifact_id = art.artifact_id) " - + //NON-NLS - "AND (att2.artifact_id = art.artifact_id) " - + //NON-NLS - "AND (att3.artifact_id = art.artifact_id) " - + //NON-NLS - "AND (f.obj_id = art.obj_id) " - + //NON-NLS - "AND (att1.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID() + ") " - + //NON-NLS - "AND (att2.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW.getTypeID() + ") " - + //NON-NLS - "AND (att3.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + ") " - + //NON-NLS - "AND (art.artifact_type_id = " + ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + ") " - + //NON-NLS - orderByClause; //NON-NLS - - try (CaseDbQuery dbQuery = skCase.executeQuery(keywordsQuery)) { - ResultSet resultSet = dbQuery.getResultSet(); - - String currentKeyword = ""; - String currentList = ""; - while (resultSet.next()) { - // Check to see if all the TableReportModules have been canceled - if (progressPanel.getStatus() == ReportStatus.CANCELED) { - break; - } - - // Get any tags that associated with this artifact and apply the tag filter. - HashSet uniqueTagNames = getUniqueTagNames(resultSet.getLong("artifact_id")); //NON-NLS - if (failsTagFilter(uniqueTagNames, tagNamesFilter)) { - continue; - } - String tagsList = makeCommaSeparatedList(uniqueTagNames); - - Long objId = resultSet.getLong("obj_id"); //NON-NLS - String keyword = resultSet.getString("keyword"); //NON-NLS - String preview = resultSet.getString("preview"); //NON-NLS - String list = resultSet.getString("list"); //NON-NLS - String uniquePath = ""; - - try { - AbstractFile f = skCase.getAbstractFileById(objId); - if (f != null) { - uniquePath = skCase.getAbstractFileById(objId).getUniquePath(); - } - } catch (TskCoreException ex) { - errorList.add( - NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetAbstractFileByID")); - logger.log(Level.WARNING, "Failed to get Abstract File by ID.", ex); //NON-NLS - } - - // If the lists aren't the same, we've started a new list - if ((!list.equals(currentList) && !list.isEmpty()) || (list.isEmpty() && !currentList.equals( - NbBundle.getMessage(this.getClass(), "ReportGenerator.writeKwHits.userSrchs")))) { - if (!currentList.isEmpty()) { - tableModule.endTable(); - tableModule.endSet(); - } - currentList = list.isEmpty() ? NbBundle - .getMessage(this.getClass(), "ReportGenerator.writeKwHits.userSrchs") : list; - currentKeyword = ""; // reset the current keyword because it's a new list - tableModule.startSet(currentList); - progressPanel.updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processingList", - ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName(), currentList)); - } - if (!keyword.equals(currentKeyword)) { - if (!currentKeyword.equals("")) { - tableModule.endTable(); - } - currentKeyword = keyword; - tableModule.addSetElement(currentKeyword); - List columnHeaderNames = new ArrayList<>(); - columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.preview")); - columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")); - columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags")); - tableModule.startTable(columnHeaderNames); - } - - String previewreplace = EscapeUtil.escapeHtml(preview); - tableModule.addRow(Arrays.asList(new String[]{previewreplace.replaceAll(" tagNamesFilter) { - String orderByClause; - if (currentCase.getCaseType() == Case.CaseType.MULTI_USER_CASE) { - orderByClause = "ORDER BY convert_to(att.value_text, 'SQL_ASCII') ASC NULLS FIRST"; //NON-NLS - } else { - orderByClause = "ORDER BY att.value_text ASC"; //NON-NLS - } - String hashsetsQuery - = "SELECT att.value_text AS list " - + //NON-NLS - "FROM blackboard_attributes AS att, blackboard_artifacts AS art " - + //NON-NLS - "WHERE att.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + " " - + //NON-NLS - "AND art.artifact_type_id = " + ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() + " " - + //NON-NLS - "AND att.artifact_id = art.artifact_id " - + //NON-NLS - "GROUP BY list " + orderByClause; //NON-NLS - - try (CaseDbQuery dbQuery = skCase.executeQuery(hashsetsQuery)) { - // Query for hashsets - ResultSet listsRs = dbQuery.getResultSet(); - List lists = new ArrayList<>(); - while (listsRs.next()) { - lists.add(listsRs.getString("list")); //NON-NLS - } - - tableModule.startDataType(ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName(), comment); - tableModule.addSetIndex(lists); - progressPanel.updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", - ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName())); - } catch (TskCoreException | SQLException ex) { - errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedQueryHashsetLists")); - logger.log(Level.SEVERE, "Failed to query hashset lists: ", ex); //NON-NLS - return; - } - - if (currentCase.getCaseType() == Case.CaseType.MULTI_USER_CASE) { - orderByClause = "ORDER BY convert_to(att.value_text, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS - + "convert_to(f.parent_path, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS - + "convert_to(f.name, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS - + "size ASC NULLS FIRST"; //NON-NLS - } else { - orderByClause = "ORDER BY att.value_text ASC, f.parent_path ASC, f.name ASC, size ASC"; //NON-NLS - } - String hashsetHitsQuery - = "SELECT art.artifact_id, art.obj_id, att.value_text AS setname, f.name AS name, f.size AS size, f.parent_path AS parent_path " - + //NON-NLS - "FROM blackboard_artifacts AS art, blackboard_attributes AS att, tsk_files AS f " - + //NON-NLS - "WHERE (att.artifact_id = art.artifact_id) " - + //NON-NLS - "AND (f.obj_id = art.obj_id) " - + //NON-NLS - "AND (att.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + ") " - + //NON-NLS - "AND (art.artifact_type_id = " + ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() + ") " - + //NON-NLS - orderByClause; //NON-NLS - - try (CaseDbQuery dbQuery = skCase.executeQuery(hashsetHitsQuery)) { - // Query for hashset hits - ResultSet resultSet = dbQuery.getResultSet(); - String currentSet = ""; - while (resultSet.next()) { - // Check to see if all the TableReportModules have been canceled - if (progressPanel.getStatus() == ReportStatus.CANCELED) { - break; - } - - // Get any tags that associated with this artifact and apply the tag filter. - HashSet uniqueTagNames = getUniqueTagNames(resultSet.getLong("artifact_id")); //NON-NLS - if (failsTagFilter(uniqueTagNames, tagNamesFilter)) { - continue; - } - String tagsList = makeCommaSeparatedList(uniqueTagNames); - - Long objId = resultSet.getLong("obj_id"); //NON-NLS - String set = resultSet.getString("setname"); //NON-NLS - String size = resultSet.getString("size"); //NON-NLS - String uniquePath = ""; - - try { - AbstractFile f = skCase.getAbstractFileById(objId); - if (f != null) { - uniquePath = skCase.getAbstractFileById(objId).getUniquePath(); - } - } catch (TskCoreException ex) { - errorList.add( - NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetAbstractFileFromID")); - logger.log(Level.WARNING, "Failed to get Abstract File from ID.", ex); //NON-NLS - return; - } - - // If the sets aren't the same, we've started a new set - if (!set.equals(currentSet)) { - if (!currentSet.isEmpty()) { - tableModule.endTable(); - tableModule.endSet(); - } - currentSet = set; - tableModule.startSet(currentSet); - List columnHeaderNames = new ArrayList<>(); - columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.file")); - columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.size")); - columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags")); - tableModule.startTable(columnHeaderNames); - progressPanel.updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processingList", - ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName(), currentSet)); - } - - // Add a row for this hit to every module - tableModule.addRow(Arrays.asList(new String[]{uniquePath, size, tagsList})); - } - - // Finish the current data type - progressPanel.increment(); - tableModule.endDataType(); - } catch (TskCoreException | SQLException ex) { - errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedQueryHashsetHits")); - logger.log(Level.SEVERE, "Failed to query hashsets hits: ", ex); //NON-NLS - } - } - - /** - * For a given artifact type ID, return the list of the columns that we are - * reporting on. - * - * @param artifactTypeId artifact type ID - * @param attributeTypeSet The set of attributeTypeSet available for this - * artifact type - * - * @return List row titles - */ - private List getArtifactTableColumns(int artifactTypeId, Set attributeTypeSet) { - ArrayList columns = new ArrayList<>(); - - // Long switch statement to retain ordering of attribute types that are - // attached to pre-defined artifact types. - if (ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID() == artifactTypeId) { - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.url"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_URL))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.title"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_TITLE))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateCreated"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PROG_NAME))); - - } else if (ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID() == artifactTypeId) { - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.url"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_URL))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_NAME))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.value"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_VALUE))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PROG_NAME))); - - } else if (ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID() == artifactTypeId) { - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.url"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_URL))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateAccessed"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.referrer"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_REFERRER))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.title"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_TITLE))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PROG_NAME))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.urlDomainDecoded"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_URL_DECODED))); - - } else if (ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID() == artifactTypeId) { - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dest"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PATH))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.sourceUrl"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_URL))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateAccessed"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PROG_NAME))); - - } else if (ARTIFACT_TYPE.TSK_RECENT_OBJECT.getTypeID() == artifactTypeId) { - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.path"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PATH))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME))); - - } else if (ARTIFACT_TYPE.TSK_INSTALLED_PROG.getTypeID() == artifactTypeId) { - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.progName"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PROG_NAME))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.instDateTime"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME))); - - } else if (ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() == artifactTypeId) { - columns.add(new HeaderOnlyColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.preview"))); - - } else if (ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() == artifactTypeId) { - columns.add(new SourceFileColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.file"))); - - columns.add(new HeaderOnlyColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.size"))); - - } else if (ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID() == artifactTypeId) { - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.devMake"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DEVICE_MAKE))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.devModel"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.deviceId"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DEVICE_ID))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME))); - - } else if (ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID() == artifactTypeId) { - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.text"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_TEXT))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.domain"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DOMAIN))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateAccessed"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.progName"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PROG_NAME))); - - } else if (ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID() == artifactTypeId) { - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTaken"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.devManufacturer"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DEVICE_MAKE))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.devModel"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.altitude"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE))); - - } else if (ARTIFACT_TYPE.TSK_CONTACT.getTypeID() == artifactTypeId) { - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.personName"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_NAME))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumber"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumHome"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_HOME))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumOffice"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_OFFICE))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumMobile"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_MOBILE))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.email"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_EMAIL))); - - } else if (ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() == artifactTypeId) { - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.msgType"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.direction"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DIRECTION))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.readStatus"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_READ_STATUS))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.fromPhoneNum"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.fromEmail"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_EMAIL_FROM))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.toPhoneNum"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.toEmail"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_EMAIL_TO))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.subject"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SUBJECT))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.text"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_TEXT))); - - } else if (ARTIFACT_TYPE.TSK_CALLLOG.getTypeID() == artifactTypeId) { - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.personName"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_NAME))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.fromPhoneNum"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.toPhoneNum"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_START))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.direction"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DIRECTION))); - - } else if (ARTIFACT_TYPE.TSK_CALENDAR_ENTRY.getTypeID() == artifactTypeId) { - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.calendarEntryType"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CALENDAR_ENTRY_TYPE))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.description"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DESCRIPTION))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.startDateTime"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_START))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.endDateTime"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_END))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.location"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_LOCATION))); - - } else if (ARTIFACT_TYPE.TSK_SPEED_DIAL_ENTRY.getTypeID() == artifactTypeId) { - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.shortCut"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SHORTCUT))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.personName"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_NAME_PERSON))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumber"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER))); - - } else if (ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING.getTypeID() == artifactTypeId) { - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.deviceName"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DEVICE_NAME))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.deviceAddress"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DEVICE_ID))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME))); - - } else if (ARTIFACT_TYPE.TSK_GPS_TRACKPOINT.getTypeID() == artifactTypeId) { - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME))); - - } else if (ARTIFACT_TYPE.TSK_GPS_BOOKMARK.getTypeID() == artifactTypeId) { - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.altitude"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_NAME))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.locationAddress"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_LOCATION))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME))); - - } else if (ARTIFACT_TYPE.TSK_GPS_LAST_KNOWN_LOCATION.getTypeID() == artifactTypeId) { - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.altitude"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_NAME))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.locationAddress"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_LOCATION))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME))); - - } else if (ARTIFACT_TYPE.TSK_GPS_SEARCH.getTypeID() == artifactTypeId) { - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.altitude"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_NAME))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.locationAddress"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_LOCATION))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME))); - - } else if (ARTIFACT_TYPE.TSK_SERVICE_ACCOUNT.getTypeID() == artifactTypeId) { - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.category"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CATEGORY))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.userId"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_USER_ID))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.password"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PASSWORD))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.personName"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_NAME))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.appName"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PROG_NAME))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.url"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_URL))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.appPath"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PATH))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.description"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DESCRIPTION))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.replytoAddress"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_EMAIL_REPLYTO))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.mailServer"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SERVER_NAME))); - - } else if (ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID() == artifactTypeId) { - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_NAME))); - - } else if (ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID() == artifactTypeId) { - columns.add(new HeaderOnlyColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.file"))); - - columns.add(new HeaderOnlyColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.extension.text"))); - - columns.add(new HeaderOnlyColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.mimeType.text"))); - - columns.add(new HeaderOnlyColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.path"))); - - } else if (ARTIFACT_TYPE.TSK_OS_INFO.getTypeID() == artifactTypeId) { - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.processorArchitecture.text"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PROCESSOR_ARCHITECTURE))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.osName.text"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PROG_NAME))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.osInstallDate.text"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME))); - - } else if (ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID() == artifactTypeId) { - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskEmailTo"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_EMAIL_TO))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskEmailFrom"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_EMAIL_FROM))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskSubject"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SUBJECT))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskDateTimeSent"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_SENT))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskDateTimeRcvd"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_RCVD))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskPath"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PATH))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskEmailCc"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_EMAIL_CC))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskEmailBcc"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_EMAIL_BCC))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskMsgId"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_MSG_ID))); - - } else if (ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() == artifactTypeId) { - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskSetName"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SET_NAME))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskInterestingFilesCategory"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CATEGORY))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskPath"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PATH))); - - } else if (ARTIFACT_TYPE.TSK_GPS_ROUTE.getTypeID() == artifactTypeId) { - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskGpsRouteCategory"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CATEGORY))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitudeEnd"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_END))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitudeEnd"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_END))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitudeStart"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_START))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitudeStart"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_START))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_NAME))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.location"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_LOCATION))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PROG_NAME))); - - } else if (ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == artifactTypeId) { - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskSetName"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SET_NAME))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.associatedArtifact"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PROG_NAME))); - - } else if (ARTIFACT_TYPE.TSK_PROG_RUN.getTypeID() == artifactTypeId) { - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PROG_NAME))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.associatedArtifact"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.count"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_COUNT))); - - } else if (ARTIFACT_TYPE.TSK_OS_ACCOUNT.getTypeID() == artifactTypeId) { - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.userName"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_USER_NAME))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.userId"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_USER_ID))); - - } else if (ARTIFACT_TYPE.TSK_REMOTE_DRIVE.getTypeID() == artifactTypeId) { - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.localPath"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_LOCAL_PATH))); - - columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.remotePath"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_REMOTE_PATH))); - } else { - // This is the case that it is a custom type. The reason an else is - // necessary is to make sure that the source file column is added - for (BlackboardAttribute.Type type : attributeTypeSet) { - columns.add(new AttributeColumn(type.getDisplayName(), type)); - } - columns.add(new SourceFileColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile"))); - columns.add(new TaggedResultsColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags"))); - - // Short circuits to guarantee that the attribute types aren't added - // twice. - return columns; - } - // If it is an attribute column, it removes the attribute type of that - // column from the set, so types are not reported more than once. - for (Column column : columns) { - attributeTypeSet = column.removeTypeFromSet(attributeTypeSet); - } - // Now uses the remaining types in the set to construct columns - for (BlackboardAttribute.Type type : attributeTypeSet) { - columns.add(new AttributeColumn(type.getDisplayName(), type)); - } - // Source file column is added here for ordering purposes. - if (artifactTypeId == ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID() - || artifactTypeId == ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID() - || artifactTypeId == ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID() - || artifactTypeId == ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID() - || artifactTypeId == ARTIFACT_TYPE.TSK_RECENT_OBJECT.getTypeID() - || artifactTypeId == ARTIFACT_TYPE.TSK_INSTALLED_PROG.getTypeID() - || artifactTypeId == ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID() - || artifactTypeId == ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID() - || artifactTypeId == ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID() - || artifactTypeId == ARTIFACT_TYPE.TSK_CONTACT.getTypeID() - || artifactTypeId == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() - || artifactTypeId == ARTIFACT_TYPE.TSK_CALLLOG.getTypeID() - || artifactTypeId == ARTIFACT_TYPE.TSK_CALENDAR_ENTRY.getTypeID() - || artifactTypeId == ARTIFACT_TYPE.TSK_SPEED_DIAL_ENTRY.getTypeID() - || artifactTypeId == ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING.getTypeID() - || artifactTypeId == ARTIFACT_TYPE.TSK_GPS_TRACKPOINT.getTypeID() - || artifactTypeId == ARTIFACT_TYPE.TSK_GPS_BOOKMARK.getTypeID() - || artifactTypeId == ARTIFACT_TYPE.TSK_GPS_LAST_KNOWN_LOCATION.getTypeID() - || artifactTypeId == ARTIFACT_TYPE.TSK_GPS_SEARCH.getTypeID() - || artifactTypeId == ARTIFACT_TYPE.TSK_SERVICE_ACCOUNT.getTypeID() - || artifactTypeId == ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID() - || artifactTypeId == ARTIFACT_TYPE.TSK_OS_INFO.getTypeID()) { - columns.add(new SourceFileColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile"))); - } - columns.add(new TaggedResultsColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags"))); - - return columns; - } - - /** - * Converts a collection of strings into a single string of comma-separated - * items - * - * @param items A collection of strings - * - * @return A string of comma-separated items - */ - private String makeCommaSeparatedList(Collection items) { - String list = ""; - for (Iterator iterator = items.iterator(); iterator.hasNext();) { - list += iterator.next() + (iterator.hasNext() ? ", " : ""); - } - return list; - } - - /** - * Given a tsk_file's obj_id, return the unique path of that file. - * - * @param objId tsk_file obj_id - * - * @return String unique path - */ - private String getFileUniquePath(Content content) { - try { - if (content != null) { - return content.getUniquePath(); - } else { - return ""; - } - } catch (TskCoreException ex) { - errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetAbstractFileByID")); - logger.log(Level.WARNING, "Failed to get Abstract File by ID.", ex); //NON-NLS - } - return ""; - - } - - /** - * Container class that holds data about an Artifact to eliminate duplicate - * calls to the Sleuthkit database. - */ - private class ArtifactData implements Comparable { - - private BlackboardArtifact artifact; - private List attributes; - private HashSet tags; - private List rowData = null; - private Content content; - - ArtifactData(BlackboardArtifact artifact, List attrs, HashSet tags) { - this.artifact = artifact; - this.attributes = attrs; - this.tags = tags; - try { - this.content = Case.getCurrentCase().getSleuthkitCase().getContentById(artifact.getObjectID()); - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Could not get content from database"); - } - } - - public BlackboardArtifact getArtifact() { - return artifact; - } - - public List getAttributes() { - return attributes; - } - - public HashSet getTags() { - return tags; - } - - public long getArtifactID() { - return artifact.getArtifactID(); - } - - public long getObjectID() { - return artifact.getObjectID(); - } - - /** - * @return the content - */ - public Content getContent() { - return content; - } - - /** - * Compares ArtifactData objects by the first attribute they have in - * common in their List. Should only be used on two - * artifacts of the same type - * - * If all attributes are the same, they are assumed duplicates and are - * compared by their artifact id. Should only be used with attributes of - * the same type. - */ - @Override - public int compareTo(ArtifactData otherArtifactData) { - List thisRow = getRow(); - List otherRow = otherArtifactData.getRow(); - for (int i = 0; i < thisRow.size(); i++) { - int compare = thisRow.get(i).compareTo(otherRow.get(i)); - if (compare != 0) { - return compare; - } - } - return ((Long) this.getArtifactID()).compareTo((Long) otherArtifactData.getArtifactID()); - } - - /** - * Get the values for each row in the table report. - * - * the value types of custom artifacts - * - * @return A list of string representing the data for this artifact. - */ - public List getRow() { - if (rowData == null) { - try { - rowData = getOrderedRowDataAsStrings(); - // If else is done so that row data is not set before - // columns are added to the hash map. - if (rowData.size() > 0) { - // replace null values if attribute was not defined - for (int i = 0; i < rowData.size(); i++) { - if (rowData.get(i) == null) { - rowData.set(i, ""); - } - } - } else { - rowData = null; - return new ArrayList<>(); - } - } catch (TskCoreException ex) { - errorList.add( - NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.coreExceptionWhileGenRptRow")); - logger.log(Level.WARNING, "Core exception while generating row data for artifact report.", ex); //NON-NLS - rowData = Collections.emptyList(); - } - } - return rowData; - } - - /** - * Get a list of Strings with all the row values for the Artifact in the - * correct order to be written to the report. - * - * @return List row values. Values could be null if attribute is - * not defined in artifact - * - * @throws TskCoreException - */ - private List getOrderedRowDataAsStrings() throws TskCoreException { - - List orderedRowData = new ArrayList<>(); - if (ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID() == getArtifact().getArtifactTypeID()) { - if (content != null && content instanceof AbstractFile) { - AbstractFile file = (AbstractFile) content; - orderedRowData.add(file.getName()); - orderedRowData.add(file.getNameExtension()); - String mimeType = file.getMIMEType(); - if (mimeType == null) { - orderedRowData.add(""); - } else { - orderedRowData.add(mimeType); - } - orderedRowData.add(file.getUniquePath()); - } else { - // Make empty rows to make sure the formatting is correct - orderedRowData.add(null); - orderedRowData.add(null); - orderedRowData.add(null); - orderedRowData.add(null); - } - orderedRowData.add(makeCommaSeparatedList(getTags())); - - } else if (ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() == getArtifact().getArtifactTypeID()) { - String[] attributeDataArray = new String[3]; - // Array is used so that the order of the attributes is - // maintained. - for (BlackboardAttribute attr : attributes) { - if (attr.getAttributeType().equals(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SET_NAME))) { - attributeDataArray[0] = attr.getDisplayString(); - } else if (attr.getAttributeType().equals(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CATEGORY))) { - attributeDataArray[1] = attr.getDisplayString(); - } else if (attr.getAttributeType().equals(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PATH))) { - String pathToShow = attr.getDisplayString(); - if (pathToShow.isEmpty()) { - pathToShow = getFileUniquePath(content); - } - attributeDataArray[2] = pathToShow; - } - } - orderedRowData.addAll(Arrays.asList(attributeDataArray)); - orderedRowData.add(makeCommaSeparatedList(getTags())); - - } else if (ReportGenerator.this.columnHeaderMap.containsKey(this.artifact.getArtifactTypeID())) { - - for (Column currColumn : ReportGenerator.this.columnHeaderMap.get(this.artifact.getArtifactTypeID())) { - String cellData = currColumn.getCellData(this); - orderedRowData.add(cellData); - } - } - - return orderedRowData; - } - - } - - /** - * Get any tags associated with an artifact - * - * @param artifactId - * - * @return hash set of tag display names - * - * @throws SQLException - */ - @SuppressWarnings("deprecation") - private HashSet getUniqueTagNames(long artifactId) throws TskCoreException { - HashSet uniqueTagNames = new HashSet<>(); - - String query = "SELECT display_name, artifact_id FROM tag_names AS tn, blackboard_artifact_tags AS bat " - + //NON-NLS - "WHERE tn.tag_name_id = bat.tag_name_id AND bat.artifact_id = " + artifactId; //NON-NLS - - try (CaseDbQuery dbQuery = skCase.executeQuery(query)) { - ResultSet tagNameRows = dbQuery.getResultSet(); - while (tagNameRows.next()) { - uniqueTagNames.add(tagNameRows.getString("display_name")); //NON-NLS - } - } catch (TskCoreException | SQLException ex) { - throw new TskCoreException("Error getting tag names for artifact: ", ex); - } - - return uniqueTagNames; - - } - - private interface Column { - - String getColumnHeader(); - - String getCellData(ArtifactData artData); - - Set removeTypeFromSet(Set types); - } - - private class AttributeColumn implements Column { - - private String columnHeader; - private BlackboardAttribute.Type attributeType; - - /** - * Constructs an ArtifactCell - * - * @param columnHeader The header text of this column - * @param attributeType The attribute type associated with this column - */ - AttributeColumn(String columnHeader, BlackboardAttribute.Type attributeType) { - this.columnHeader = Objects.requireNonNull(columnHeader); - this.attributeType = attributeType; - } - - @Override - public String getColumnHeader() { - return this.columnHeader; - } - - @Override - public String getCellData(ArtifactData artData) { - List attributes = artData.getAttributes(); - for (BlackboardAttribute attribute : attributes) { - if (attribute.getAttributeType().equals(this.attributeType)) { - if (attribute.getAttributeType().getValueType() != BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME) { - return attribute.getDisplayString(); - } else { - return ContentUtils.getStringTime(attribute.getValueLong(), artData.getContent()); - } - } - } - return ""; - } - - @Override - public Set removeTypeFromSet(Set types) { - types.remove(this.attributeType); - return types; - } - } - - private class SourceFileColumn implements Column { - - private String columnHeader; - - SourceFileColumn(String columnHeader) { - this.columnHeader = columnHeader; - } - - @Override - public String getColumnHeader() { - return this.columnHeader; - } - - @Override - public String getCellData(ArtifactData artData) { - return getFileUniquePath(artData.getContent()); - /*else if (this.columnHeader.equals(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags"))) { - return makeCommaSeparatedList(artData.getTags()); - } - return "";*/ - } - - @Override - public Set removeTypeFromSet(Set types) { - // This column doesn't have a type, so nothing to remove - return types; - } - } - - private class TaggedResultsColumn implements Column { - - private String columnHeader; - - TaggedResultsColumn(String columnHeader) { - this.columnHeader = columnHeader; - } - - @Override - public String getColumnHeader() { - return this.columnHeader; - } - - @Override - public String getCellData(ArtifactData artData) { - return makeCommaSeparatedList(artData.getTags()); - } - - @Override - public Set removeTypeFromSet(Set types) { - // This column doesn't have a type, so nothing to remove - return types; - } - } - - private class HeaderOnlyColumn implements Column { - - private String columnHeader; - - HeaderOnlyColumn(String columnHeader) { - this.columnHeader = columnHeader; - } - - @Override - public String getColumnHeader() { - return columnHeader; - } - - @Override - public String getCellData(ArtifactData artData) { - throw new UnsupportedOperationException("Cannot get cell data of unspecified column"); - } - - @Override - public Set removeTypeFromSet(Set types) { - // This column doesn't have a type, so nothing to remove - return types; + MessageNotifyUtil.Notify.show( + NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorTitle"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorText") + ex.getLocalizedMessage(), + MessageNotifyUtil.MessageType.ERROR); + logger.log(Level.SEVERE, "failed to generate reports. Unable to get all files in the image.", ex); //NON-NLS + return Collections.emptyList(); } } } diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java b/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java index 0e350e12d1..3c274c919f 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java @@ -1,4 +1,4 @@ - /* +/* * * Autopsy Forensic Browser * @@ -68,10 +68,16 @@ public final class ReportWizardAction extends CallableSystemAction implements Pr ReportGenerator generator = new ReportGenerator((TableReportModule) wiz.getProperty("tableModule"), //NON-NLS (GeneralReportModule) wiz.getProperty("generalModule"), //NON-NLS (FileReportModule) wiz.getProperty("fileModule")); //NON-NLS - generator.generateTableReports((Map) wiz.getProperty("artifactStates"), (Map) wiz.getProperty("tagStates")); //NON-NLS - generator.generateFileListReports((Map) wiz.getProperty("fileReportOptions")); //NON-NLS - generator.generateGeneralReports(); - generator.displayProgressPanels(); + TableReportModule tableReport = (TableReportModule) wiz.getProperty("tableModule"); + GeneralReportModule generalReport = (GeneralReportModule) wiz.getProperty("generalModule"); + FileReportModule fileReport = (FileReportModule) wiz.getProperty("fileModule"); + if (tableReport != null) { + generator.generateTableReport(tableReport, (Map) wiz.getProperty("artifactStates"), (Map) wiz.getProperty("tagStates")); //NON-NLS + } else if (generalReport != null) { + generator.generateGeneralReport(generalReport); + } else if (fileReport != null) { + generator.generateFileListReport(fileReport, (Map) wiz.getProperty("fileReportOptions")); //NON-NLS + } } } diff --git a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java new file mode 100755 index 0000000000..16e32b8461 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java @@ -0,0 +1,1680 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * 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. + */ +package org.sleuthkit.autopsy.report; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.TreeSet; +import java.util.logging.Level; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.EscapeUtil; +import org.sleuthkit.autopsy.coreutils.ImageUtils; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.ContentUtils; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardArtifactTag; +import org.sleuthkit.datamodel.BlackboardAttribute; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; + +class TableReportGenerator { + + private final List artifactTypes = new ArrayList<>(); + private final HashSet tagNamesFilter = new HashSet<>(); + + private final List images = new ArrayList<>(); + private final ReportProgressPanel progressPanel; + private final TableReportModule tableReport; + private final Map> columnHeaderMap; + private static final Logger logger = Logger.getLogger(TableReportGenerator.class.getName()); + + private final List errorList; + + TableReportGenerator(Map artifactTypeSelections, Map tagNameSelections, ReportProgressPanel progressPanel, TableReportModule tableReport) { + + this.progressPanel = progressPanel; + this.tableReport = tableReport; + this.columnHeaderMap = new HashMap<>(); + errorList = new ArrayList<>(); + // Get the artifact types selected by the user. + for (Map.Entry entry : artifactTypeSelections.entrySet()) { + if (entry.getValue()) { + artifactTypes.add(entry.getKey()); + } + } + + // Get the tag names selected by the user and make a tag names filter. + if (null != tagNameSelections) { + for (Map.Entry entry : tagNameSelections.entrySet()) { + if (entry.getValue() == true) { + tagNamesFilter.add(entry.getKey()); + } + } + } + } + + protected void execute() { + // Start the progress indicators for each active TableReportModule. + + progressPanel.start(); + progressPanel.setIndeterminate(false); + progressPanel.setMaximumProgress(this.artifactTypes.size() + 2); // +2 for content and blackboard artifact tags + // report on the blackboard results + if (progressPanel.getStatus() != ReportProgressPanel.ReportStatus.CANCELED) { + makeBlackboardArtifactTables(); + } + + // report on the tagged files and artifacts + if (progressPanel.getStatus() != ReportProgressPanel.ReportStatus.CANCELED) { + makeContentTagsTables(); + } + + if (progressPanel.getStatus() != ReportProgressPanel.ReportStatus.CANCELED) { + makeBlackboardArtifactTagsTables(); + } + + if (progressPanel.getStatus() != ReportProgressPanel.ReportStatus.CANCELED) { + // report on the tagged images + makeThumbnailTable(); + } + + // finish progress, wrap up + progressPanel.complete(ReportProgressPanel.ReportStatus.COMPLETE); + } + + /** + * Generate the tables for the selected blackboard artifacts + */ + private void makeBlackboardArtifactTables() { + // Make a comment string describing the tag names filter in effect. + StringBuilder comment = new StringBuilder(); + if (!tagNamesFilter.isEmpty()) { + comment.append(NbBundle.getMessage(this.getClass(), "ReportGenerator.artifactTable.taggedResults.text")); + comment.append(makeCommaSeparatedList(tagNamesFilter)); + } + + // Add a table to the report for every enabled blackboard artifact type. + for (BlackboardArtifact.Type type : artifactTypes) { + // Check for cancellaton. + + if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) { + return; + } + + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", + type.getDisplayName())); + + // Keyword hits and hashset hit artifacts get special handling. + if (type.getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { + writeKeywordHits(tableReport, comment.toString(), tagNamesFilter); + continue; + } else if (type.getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) { + writeHashsetHits(tableReport, comment.toString(), tagNamesFilter); + continue; + } + + List artifactList = getFilteredArtifacts(type, tagNamesFilter); + + if (artifactList.isEmpty()) { + continue; + } + + /* + Gets all of the attribute types of this artifact type by adding + all of the types to a set + */ + Set attrTypeSet = new TreeSet<>((BlackboardAttribute.Type o1, BlackboardAttribute.Type o2) -> o1.getDisplayName().compareTo(o2.getDisplayName())); + for (ArtifactData data : artifactList) { + List attributes = data.getAttributes(); + for (BlackboardAttribute attribute : attributes) { + attrTypeSet.add(attribute.getAttributeType()); + } + } + // Get the columns appropriate for the artifact type. This is + // used to get the data that will be in the cells below based on + // type, and display the column headers. + List columns = getArtifactTableColumns(type.getTypeID(), attrTypeSet); + if (columns.isEmpty()) { + continue; + } + columnHeaderMap.put(type.getTypeID(), columns); + + // The artifact list is sorted now, as getting the row data is + // dependent on having the columns, which is necessary for + // sorting. + Collections.sort(artifactList); + List columnHeaderNames = new ArrayList<>(); + for (Column currColumn : columns) { + columnHeaderNames.add(currColumn.getColumnHeader()); + } + + tableReport.startDataType(type.getDisplayName(), comment.toString()); + tableReport.startTable(columnHeaderNames); + for (ArtifactData artifactData : artifactList) { + // Get the row data for this artifact, and has the + // module add it. + List rowData = artifactData.getRow(); + if (rowData.isEmpty()) { + continue; + } + + tableReport.addRow(rowData); + } + // Finish up this data type + progressPanel.increment(); + tableReport.endTable(); + tableReport.endDataType(); + } + } + + /** + * Make table for tagged files + */ + @SuppressWarnings("deprecation") + private void makeContentTagsTables() { + + // Get the content tags. + List tags; + try { + tags = Case.getCurrentCase().getServices().getTagsManager().getAllContentTags(); + } catch (TskCoreException ex) { + errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetContentTags")); + logger.log(Level.SEVERE, "failed to get content tags", ex); //NON-NLS + return; + } + + // Tell the modules reporting on content tags is beginning. + // @@@ This casting is a tricky little workaround to allow the HTML report module to slip in a content hyperlink. + // @@@ Alos Using the obsolete ARTIFACT_TYPE.TSK_TAG_FILE is also an expedient hack. + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", + BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName())); + ArrayList columnHeaders = new ArrayList<>(Arrays.asList( + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.tag"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.file"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.comment"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeModified"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeChanged"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeAccessed"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeCreated"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.size"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.hash"))); + + StringBuilder comment = new StringBuilder(); + if (!tagNamesFilter.isEmpty()) { + comment.append( + NbBundle.getMessage(this.getClass(), "ReportGenerator.makeContTagTab.taggedFiles.msg")); + comment.append(makeCommaSeparatedList(tagNamesFilter)); + } + if (tableReport instanceof ReportHTML) { + ReportHTML htmlReportModule = (ReportHTML) tableReport; + htmlReportModule.startDataType(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName(), comment.toString()); + htmlReportModule.startContentTagsTable(columnHeaders); + } else { + tableReport.startDataType(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName(), comment.toString()); + tableReport.startTable(columnHeaders); + } + + // Give the modules the rows for the content tags. + for (ContentTag tag : tags) { + // skip tags that we are not reporting on + if (passesTagNamesFilter(tag.getName().getDisplayName()) == false) { + continue; + } + + String fileName; + try { + fileName = tag.getContent().getUniquePath(); + } catch (TskCoreException ex) { + fileName = tag.getContent().getName(); + } + + ArrayList rowData = new ArrayList<>(Arrays.asList(tag.getName().getDisplayName(), fileName, tag.getComment())); + Content content = tag.getContent(); + if (content instanceof AbstractFile) { + AbstractFile file = (AbstractFile) content; + + // Add metadata about the file to HTML output + rowData.add(file.getMtimeAsDate()); + rowData.add(file.getCtimeAsDate()); + rowData.add(file.getAtimeAsDate()); + rowData.add(file.getCrtimeAsDate()); + rowData.add(Long.toString(file.getSize())); + rowData.add(file.getMd5Hash()); + } + // @@@ This casting is a tricky little workaround to allow the HTML report module to slip in a content hyperlink. + if (tableReport instanceof ReportHTML) { + ReportHTML htmlReportModule = (ReportHTML) tableReport; + htmlReportModule.addRowWithTaggedContentHyperlink(rowData, tag); + } else { + tableReport.addRow(rowData); + } + + // see if it is for an image so that we later report on it + checkIfTagHasImage(tag); + } + + // The the modules content tags reporting is ended. + progressPanel.increment(); + tableReport.endTable(); + tableReport.endDataType(); + } + + /** + * Generate the tables for the tagged artifacts + */ + @SuppressWarnings("deprecation") + private void makeBlackboardArtifactTagsTables() { + + List tags; + try { + tags = Case.getCurrentCase().getServices().getTagsManager().getAllBlackboardArtifactTags(); + } catch (TskCoreException ex) { + errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetBBArtifactTags")); + logger.log(Level.SEVERE, "failed to get blackboard artifact tags", ex); //NON-NLS + return; + } + + // Tell the modules reporting on blackboard artifact tags data type is beginning. + // @@@ Using the obsolete ARTIFACT_TYPE.TSK_TAG_ARTIFACT is an expedient hack. + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", + BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getDisplayName())); + StringBuilder comment = new StringBuilder(); + if (!tagNamesFilter.isEmpty()) { + comment.append( + NbBundle.getMessage(this.getClass(), "ReportGenerator.makeBbArtTagTab.taggedRes.msg")); + comment.append(makeCommaSeparatedList(tagNamesFilter)); + } + tableReport.startDataType(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getDisplayName(), comment.toString()); + tableReport.startTable(new ArrayList<>(Arrays.asList( + NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.resultType"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.tag"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.comment"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.srcFile")))); + + // Give the modules the rows for the content tags. + for (BlackboardArtifactTag tag : tags) { + if (passesTagNamesFilter(tag.getName().getDisplayName()) == false) { + continue; + } + + List row; + row = new ArrayList<>(Arrays.asList(tag.getArtifact().getArtifactTypeName(), tag.getName().getDisplayName(), tag.getComment(), tag.getContent().getName())); + tableReport.addRow(row); + + // check if the tag is an image that we should later make a thumbnail for + checkIfTagHasImage(tag); + } + + // The the modules blackboard artifact tags reporting is ended. + progressPanel.increment(); + tableReport.endTable(); + tableReport.endDataType(); + } + + /** + * Test if the user requested that this tag be reported on + * + * @param tagName + * + * @return true if it should be reported on + */ + private boolean passesTagNamesFilter(String tagName) { + return tagNamesFilter.isEmpty() || tagNamesFilter.contains(tagName); + } + + /** + * Make a report for the files that were previously found to be images. + */ + private void makeThumbnailTable() { + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.createdThumb.text")); + + if (tableReport instanceof ReportHTML) { + ReportHTML htmlModule = (ReportHTML) tableReport; + htmlModule.startDataType( + NbBundle.getMessage(this.getClass(), "ReportGenerator.thumbnailTable.name"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.thumbnailTable.desc")); + List emptyHeaders = new ArrayList<>(); + for (int i = 0; i < ReportHTML.THUMBNAIL_COLUMNS; i++) { + emptyHeaders.add(""); + } + htmlModule.startTable(emptyHeaders); + + htmlModule.addThumbnailRows(images); + + htmlModule.endTable(); + htmlModule.endDataType(); + } + + } + + /** + * Analyze artifact associated with tag and add to internal list if it is + * associated with an image. + * + * @param artifactTag + */ + private void checkIfTagHasImage(BlackboardArtifactTag artifactTag) { + AbstractFile file; + try { + file = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(artifactTag.getArtifact().getObjectID()); + } catch (TskCoreException ex) { + errorList.add( + NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.errGetContentFromBBArtifact")); + logger.log(Level.WARNING, "Error while getting content from a blackboard artifact to report on.", ex); //NON-NLS + return; + } + + if (file != null) { + checkIfFileIsImage(file); + } + } + + /** + * Analyze file that tag is associated with and determine if it is an image + * and should have a thumbnail reported for it. Images are added to internal + * list. + * + * @param contentTag + */ + private void checkIfTagHasImage(ContentTag contentTag) { + Content c = contentTag.getContent(); + if (c instanceof AbstractFile == false) { + return; + } + checkIfFileIsImage((AbstractFile) c); + } + + /** + * If file is an image file, add it to the internal 'images' list. + * + * @param file + */ + private void checkIfFileIsImage(AbstractFile file) { + + if (file.isDir() + || file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS + || file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) { + return; + } + + if (ImageUtils.thumbnailSupported(file)) { + images.add(file); + } + } + + /** + * Converts a collection of strings into a single string of comma-separated + * items + * + * @param items A collection of strings + * + * @return A string of comma-separated items + */ + private String makeCommaSeparatedList(Collection items) { + String list = ""; + for (Iterator iterator = items.iterator(); iterator.hasNext();) { + list += iterator.next() + (iterator.hasNext() ? ", " : ""); + } + return list; + } + + /** + * Write the keyword hits to the provided TableReportModules. + * + * @param tableModule module to report on + */ + @SuppressWarnings("deprecation") + private void writeKeywordHits(TableReportModule tableModule, String comment, HashSet tagNamesFilter) { + + // Query for keyword lists-only so that we can tell modules what lists + // will exist for their index. + // @@@ There is a bug in here. We should use the tags in the below code + // so that we only report the lists that we will later provide with real + // hits. If no keyord hits are tagged, then we make the page for nothing. + String orderByClause; + if (Case.getCurrentCase().getCaseType() == Case.CaseType.MULTI_USER_CASE) { + orderByClause = "ORDER BY convert_to(att.value_text, 'SQL_ASCII') ASC NULLS FIRST"; //NON-NLS + } else { + orderByClause = "ORDER BY list ASC"; //NON-NLS + } + String keywordListQuery + = "SELECT att.value_text AS list " + + //NON-NLS + "FROM blackboard_attributes AS att, blackboard_artifacts AS art " + + //NON-NLS + "WHERE att.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + " " + + //NON-NLS + "AND art.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + " " + + //NON-NLS + "AND att.artifact_id = art.artifact_id " + + //NON-NLS + "GROUP BY list " + orderByClause; //NON-NLS + + try (SleuthkitCase.CaseDbQuery dbQuery = Case.getCurrentCase().getSleuthkitCase().executeQuery(keywordListQuery)) { + ResultSet listsRs = dbQuery.getResultSet(); + List lists = new ArrayList<>(); + while (listsRs.next()) { + String list = listsRs.getString("list"); //NON-NLS + if (list.isEmpty()) { + list = NbBundle.getMessage(this.getClass(), "ReportGenerator.writeKwHits.userSrchs"); + } + lists.add(list); + } + + // Make keyword data type and give them set index + tableModule.startDataType(BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName(), comment); + tableModule.addSetIndex(lists); + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", + BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName())); + } catch (TskCoreException | SQLException ex) { + errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedQueryKWLists")); + logger.log(Level.SEVERE, "Failed to query keyword lists: ", ex); //NON-NLS + return; + } + + if (Case.getCurrentCase().getCaseType() == Case.CaseType.MULTI_USER_CASE) { + orderByClause = "ORDER BY convert_to(att3.value_text, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS + + "convert_to(att1.value_text, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS + + "convert_to(f.parent_path, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS + + "convert_to(f.name, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS + + "convert_to(att2.value_text, 'SQL_ASCII') ASC NULLS FIRST"; //NON-NLS + } else { + orderByClause = "ORDER BY list ASC, keyword ASC, parent_path ASC, name ASC, preview ASC"; //NON-NLS + } + // Query for keywords, grouped by list + String keywordsQuery + = "SELECT art.artifact_id, art.obj_id, att1.value_text AS keyword, att2.value_text AS preview, att3.value_text AS list, f.name AS name, f.parent_path AS parent_path " + + //NON-NLS + "FROM blackboard_artifacts AS art, blackboard_attributes AS att1, blackboard_attributes AS att2, blackboard_attributes AS att3, tsk_files AS f " + + //NON-NLS + "WHERE (att1.artifact_id = art.artifact_id) " + + //NON-NLS + "AND (att2.artifact_id = art.artifact_id) " + + //NON-NLS + "AND (att3.artifact_id = art.artifact_id) " + + //NON-NLS + "AND (f.obj_id = art.obj_id) " + + //NON-NLS + "AND (att1.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID() + ") " + + //NON-NLS + "AND (att2.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW.getTypeID() + ") " + + //NON-NLS + "AND (att3.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + ") " + + //NON-NLS + "AND (art.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + ") " + + //NON-NLS + orderByClause; //NON-NLS + + try (SleuthkitCase.CaseDbQuery dbQuery = Case.getCurrentCase().getSleuthkitCase().executeQuery(keywordsQuery)) { + ResultSet resultSet = dbQuery.getResultSet(); + + String currentKeyword = ""; + String currentList = ""; + while (resultSet.next()) { + // Check to see if all the TableReportModules have been canceled + if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) { + break; + } + + // Get any tags that associated with this artifact and apply the tag filter. + HashSet uniqueTagNames = getUniqueTagNames(resultSet.getLong("artifact_id")); //NON-NLS + if (failsTagFilter(uniqueTagNames, tagNamesFilter)) { + continue; + } + String tagsList = makeCommaSeparatedList(uniqueTagNames); + + Long objId = resultSet.getLong("obj_id"); //NON-NLS + String keyword = resultSet.getString("keyword"); //NON-NLS + String preview = resultSet.getString("preview"); //NON-NLS + String list = resultSet.getString("list"); //NON-NLS + String uniquePath = ""; + + try { + AbstractFile f = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(objId); + if (f != null) { + uniquePath = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(objId).getUniquePath(); + } + } catch (TskCoreException ex) { + errorList.add( + NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetAbstractFileByID")); + logger.log(Level.WARNING, "Failed to get Abstract File by ID.", ex); //NON-NLS + } + + // If the lists aren't the same, we've started a new list + if ((!list.equals(currentList) && !list.isEmpty()) || (list.isEmpty() && !currentList.equals( + NbBundle.getMessage(this.getClass(), "ReportGenerator.writeKwHits.userSrchs")))) { + if (!currentList.isEmpty()) { + tableModule.endTable(); + tableModule.endSet(); + } + currentList = list.isEmpty() ? NbBundle + .getMessage(this.getClass(), "ReportGenerator.writeKwHits.userSrchs") : list; + currentKeyword = ""; // reset the current keyword because it's a new list + tableModule.startSet(currentList); + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processingList", + BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName(), currentList)); + } + if (!keyword.equals(currentKeyword)) { + if (!currentKeyword.equals("")) { + tableModule.endTable(); + } + currentKeyword = keyword; + tableModule.addSetElement(currentKeyword); + List columnHeaderNames = new ArrayList<>(); + columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.preview")); + columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")); + columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags")); + tableModule.startTable(columnHeaderNames); + } + + String previewreplace = EscapeUtil.escapeHtml(preview); + tableModule.addRow(Arrays.asList(new String[]{previewreplace.replaceAll(" tagNamesFilter) { + String orderByClause; + if (Case.getCurrentCase().getCaseType() == Case.CaseType.MULTI_USER_CASE) { + orderByClause = "ORDER BY convert_to(att.value_text, 'SQL_ASCII') ASC NULLS FIRST"; //NON-NLS + } else { + orderByClause = "ORDER BY att.value_text ASC"; //NON-NLS + } + String hashsetsQuery + = "SELECT att.value_text AS list " + + //NON-NLS + "FROM blackboard_attributes AS att, blackboard_artifacts AS art " + + //NON-NLS + "WHERE att.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + " " + + //NON-NLS + "AND art.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() + " " + + //NON-NLS + "AND att.artifact_id = art.artifact_id " + + //NON-NLS + "GROUP BY list " + orderByClause; //NON-NLS + + try (SleuthkitCase.CaseDbQuery dbQuery = Case.getCurrentCase().getSleuthkitCase().executeQuery(hashsetsQuery)) { + // Query for hashsets + ResultSet listsRs = dbQuery.getResultSet(); + List lists = new ArrayList<>(); + while (listsRs.next()) { + lists.add(listsRs.getString("list")); //NON-NLS + } + + tableModule.startDataType(BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName(), comment); + tableModule.addSetIndex(lists); + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", + BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName())); + } catch (TskCoreException | SQLException ex) { + errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedQueryHashsetLists")); + logger.log(Level.SEVERE, "Failed to query hashset lists: ", ex); //NON-NLS + return; + } + + if (Case.getCurrentCase().getCaseType() == Case.CaseType.MULTI_USER_CASE) { + orderByClause = "ORDER BY convert_to(att.value_text, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS + + "convert_to(f.parent_path, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS + + "convert_to(f.name, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS + + "size ASC NULLS FIRST"; //NON-NLS + } else { + orderByClause = "ORDER BY att.value_text ASC, f.parent_path ASC, f.name ASC, size ASC"; //NON-NLS + } + String hashsetHitsQuery + = "SELECT art.artifact_id, art.obj_id, att.value_text AS setname, f.name AS name, f.size AS size, f.parent_path AS parent_path " + + //NON-NLS + "FROM blackboard_artifacts AS art, blackboard_attributes AS att, tsk_files AS f " + + //NON-NLS + "WHERE (att.artifact_id = art.artifact_id) " + + //NON-NLS + "AND (f.obj_id = art.obj_id) " + + //NON-NLS + "AND (att.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + ") " + + //NON-NLS + "AND (art.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() + ") " + + //NON-NLS + orderByClause; //NON-NLS + + try (SleuthkitCase.CaseDbQuery dbQuery = Case.getCurrentCase().getSleuthkitCase().executeQuery(hashsetHitsQuery)) { + // Query for hashset hits + ResultSet resultSet = dbQuery.getResultSet(); + String currentSet = ""; + while (resultSet.next()) { + // Check to see if all the TableReportModules have been canceled + if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) { + break; + } + + // Get any tags that associated with this artifact and apply the tag filter. + HashSet uniqueTagNames = getUniqueTagNames(resultSet.getLong("artifact_id")); //NON-NLS + if (failsTagFilter(uniqueTagNames, tagNamesFilter)) { + continue; + } + String tagsList = makeCommaSeparatedList(uniqueTagNames); + + Long objId = resultSet.getLong("obj_id"); //NON-NLS + String set = resultSet.getString("setname"); //NON-NLS + String size = resultSet.getString("size"); //NON-NLS + String uniquePath = ""; + + try { + AbstractFile f = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(objId); + if (f != null) { + uniquePath = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(objId).getUniquePath(); + } + } catch (TskCoreException ex) { + errorList.add( + NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetAbstractFileFromID")); + logger.log(Level.WARNING, "Failed to get Abstract File from ID.", ex); //NON-NLS + return; + } + + // If the sets aren't the same, we've started a new set + if (!set.equals(currentSet)) { + if (!currentSet.isEmpty()) { + tableModule.endTable(); + tableModule.endSet(); + } + currentSet = set; + tableModule.startSet(currentSet); + List columnHeaderNames = new ArrayList<>(); + columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.file")); + columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.size")); + columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags")); + tableModule.startTable(columnHeaderNames); + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processingList", + BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName(), currentSet)); + } + + // Add a row for this hit to every module + tableModule.addRow(Arrays.asList(new String[]{uniquePath, size, tagsList})); + } + + // Finish the current data type + progressPanel.increment(); + tableModule.endDataType(); + } catch (TskCoreException | SQLException ex) { + errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedQueryHashsetHits")); + logger.log(Level.SEVERE, "Failed to query hashsets hits: ", ex); //NON-NLS + } + } + + /** + * @return the errorList + */ + List getErrorList() { + return errorList; + } + + /** + * Container class that holds data about an Artifact to eliminate duplicate + * calls to the Sleuthkit database. + */ + private class ArtifactData implements Comparable { + + private BlackboardArtifact artifact; + private List attributes; + private HashSet tags; + private List rowData = null; + private Content content; + + ArtifactData(BlackboardArtifact artifact, List attrs, HashSet tags) { + this.artifact = artifact; + this.attributes = attrs; + this.tags = tags; + try { + this.content = Case.getCurrentCase().getSleuthkitCase().getContentById(artifact.getObjectID()); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Could not get content from database"); + } + } + + public BlackboardArtifact getArtifact() { + return artifact; + } + + public List getAttributes() { + return attributes; + } + + public HashSet getTags() { + return tags; + } + + public long getArtifactID() { + return artifact.getArtifactID(); + } + + public long getObjectID() { + return artifact.getObjectID(); + } + + /** + * @return the content + */ + public Content getContent() { + return content; + } + + /** + * Compares ArtifactData objects by the first attribute they have in + * common in their List. Should only be used on two + * artifacts of the same type + * + * If all attributes are the same, they are assumed duplicates and are + * compared by their artifact id. Should only be used with attributes of + * the same type. + */ + @Override + public int compareTo(ArtifactData otherArtifactData) { + List thisRow = getRow(); + List otherRow = otherArtifactData.getRow(); + for (int i = 0; i < thisRow.size(); i++) { + int compare = thisRow.get(i).compareTo(otherRow.get(i)); + if (compare != 0) { + return compare; + } + } + return ((Long) this.getArtifactID()).compareTo(otherArtifactData.getArtifactID()); + } + + /** + * Get the values for each row in the table report. + * + * the value types of custom artifacts + * + * @return A list of string representing the data for this artifact. + */ + public List getRow() { + if (rowData == null) { + try { + rowData = getOrderedRowDataAsStrings(); + // If else is done so that row data is not set before + // columns are added to the hash map. + if (rowData.size() > 0) { + // replace null values if attribute was not defined + for (int i = 0; i < rowData.size(); i++) { + if (rowData.get(i) == null) { + rowData.set(i, ""); + } + } + } else { + rowData = null; + return new ArrayList<>(); + } + } catch (TskCoreException ex) { + errorList.add( + NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.coreExceptionWhileGenRptRow")); + logger.log(Level.WARNING, "Core exception while generating row data for artifact report.", ex); //NON-NLS + rowData = Collections.emptyList(); + } + } + return rowData; + } + + /** + * Get a list of Strings with all the row values for the Artifact in the + * correct order to be written to the report. + * + * @return List row values. Values could be null if attribute is + * not defined in artifact + * + * @throws TskCoreException + */ + private List getOrderedRowDataAsStrings() throws TskCoreException { + + List orderedRowData = new ArrayList<>(); + if (BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID() == getArtifact().getArtifactTypeID()) { + if (content != null && content instanceof AbstractFile) { + AbstractFile file = (AbstractFile) content; + orderedRowData.add(file.getName()); + orderedRowData.add(file.getNameExtension()); + String mimeType = file.getMIMEType(); + if (mimeType == null) { + orderedRowData.add(""); + } else { + orderedRowData.add(mimeType); + } + orderedRowData.add(file.getUniquePath()); + } else { + // Make empty rows to make sure the formatting is correct + orderedRowData.add(null); + orderedRowData.add(null); + orderedRowData.add(null); + orderedRowData.add(null); + } + orderedRowData.add(makeCommaSeparatedList(getTags())); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() == getArtifact().getArtifactTypeID()) { + String[] attributeDataArray = new String[3]; + // Array is used so that the order of the attributes is + // maintained. + for (BlackboardAttribute attr : attributes) { + if (attr.getAttributeType().equals(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME))) { + attributeDataArray[0] = attr.getDisplayString(); + } else if (attr.getAttributeType().equals(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY))) { + attributeDataArray[1] = attr.getDisplayString(); + } else if (attr.getAttributeType().equals(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH))) { + String pathToShow = attr.getDisplayString(); + if (pathToShow.isEmpty()) { + pathToShow = getFileUniquePath(content); + } + attributeDataArray[2] = pathToShow; + } + } + orderedRowData.addAll(Arrays.asList(attributeDataArray)); + orderedRowData.add(makeCommaSeparatedList(getTags())); + + } else if (columnHeaderMap.containsKey(this.artifact.getArtifactTypeID())) { + + for (Column currColumn : columnHeaderMap.get(this.artifact.getArtifactTypeID())) { + String cellData = currColumn.getCellData(this); + orderedRowData.add(cellData); + } + } + + return orderedRowData; + } + + } + + /** + * Get a List of the artifacts and data of the given type that pass the + * given Tag Filter. + * + * @param type The artifact type to get + * @param tagNamesFilter The tag names that should be included. + * + * @return a list of the filtered tags. + */ + private List getFilteredArtifacts(BlackboardArtifact.Type type, HashSet tagNamesFilter) { + List artifacts = new ArrayList<>(); + try { + for (BlackboardArtifact artifact : Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifacts(type.getTypeID())) { + List tags = Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact); + HashSet uniqueTagNames = new HashSet<>(); + for (BlackboardArtifactTag tag : tags) { + uniqueTagNames.add(tag.getName().getDisplayName()); + } + if (failsTagFilter(uniqueTagNames, tagNamesFilter)) { + continue; + } + try { + artifacts.add(new ArtifactData(artifact, Case.getCurrentCase().getSleuthkitCase().getBlackboardAttributes(artifact), uniqueTagNames)); + } catch (TskCoreException ex) { + errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetBBAttribs")); + logger.log(Level.SEVERE, "Failed to get Blackboard Attributes when generating report.", ex); //NON-NLS + } + } + } catch (TskCoreException ex) { + errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetBBArtifacts")); + logger.log(Level.SEVERE, "Failed to get Blackboard Artifacts when generating report.", ex); //NON-NLS + } + return artifacts; + } + + private Boolean failsTagFilter(HashSet tagNames, HashSet tagsNamesFilter) { + if (null == tagsNamesFilter || tagsNamesFilter.isEmpty()) { + return false; + } + + HashSet filteredTagNames = new HashSet<>(tagNames); + filteredTagNames.retainAll(tagsNamesFilter); + return filteredTagNames.isEmpty(); + } + + /** + * For a given artifact type ID, return the list of the columns that we are + * reporting on. + * + * @param artifactTypeId artifact type ID + * @param attributeTypeSet The set of attributeTypeSet available for this + * artifact type + * + * @return List row titles + */ + private List getArtifactTableColumns(int artifactTypeId, Set attributeTypeSet) { + ArrayList columns = new ArrayList<>(); + + // Long switch statement to retain ordering of attribute types that are + // attached to pre-defined artifact types. + if (BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.url"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.title"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TITLE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateCreated"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.url"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.value"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_VALUE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.url"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateAccessed"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.referrer"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_REFERRER))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.title"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TITLE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.urlDomainDecoded"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL_DECODED))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dest"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.sourceUrl"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateAccessed"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_RECENT_OBJECT.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.path"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_INSTALLED_PROG.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.progName"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.instDateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() == artifactTypeId) { + columns.add(new HeaderOnlyColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.preview"))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() == artifactTypeId) { + columns.add(new SourceFileColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.file"))); + + columns.add(new HeaderOnlyColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.size"))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.devMake"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_MAKE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.devModel"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_MODEL))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.deviceId"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.text"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.domain"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateAccessed"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.progName"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTaken"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.devManufacturer"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_MAKE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.devModel"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_MODEL))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.altitude"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.personName"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumber"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumHome"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_HOME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumOffice"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_OFFICE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumMobile"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_MOBILE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.email"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.msgType"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.direction"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.readStatus"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_READ_STATUS))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.fromPhoneNum"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.fromEmail"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_FROM))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.toPhoneNum"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.toEmail"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_TO))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.subject"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.text"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.personName"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.fromPhoneNum"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.toPhoneNum"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.direction"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_CALENDAR_ENTRY.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.calendarEntryType"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CALENDAR_ENTRY_TYPE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.description"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.startDateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.endDateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_END))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.location"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_SPEED_DIAL_ENTRY.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.shortCut"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SHORTCUT))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.personName"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME_PERSON))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumber"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.deviceName"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.deviceAddress"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_BOOKMARK.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.altitude"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.locationAddress"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_LAST_KNOWN_LOCATION.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.altitude"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.locationAddress"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_SEARCH.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.altitude"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.locationAddress"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_SERVICE_ACCOUNT.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.category"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.userId"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_ID))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.password"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PASSWORD))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.personName"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.appName"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.url"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.appPath"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.description"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.replytoAddress"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_REPLYTO))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.mailServer"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SERVER_NAME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID() == artifactTypeId) { + columns.add(new HeaderOnlyColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.file"))); + + columns.add(new HeaderOnlyColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.extension.text"))); + + columns.add(new HeaderOnlyColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.mimeType.text"))); + + columns.add(new HeaderOnlyColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.path"))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_OS_INFO.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.processorArchitecture.text"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROCESSOR_ARCHITECTURE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.osName.text"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.osInstallDate.text"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskEmailTo"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_TO))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskEmailFrom"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_FROM))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskSubject"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskDateTimeSent"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskDateTimeRcvd"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_RCVD))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskPath"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskEmailCc"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_CC))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskEmailBcc"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_BCC))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskMsgId"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MSG_ID))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskSetName"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskInterestingFilesCategory"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskPath"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_ROUTE.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskGpsRouteCategory"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitudeEnd"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_END))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitudeEnd"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_END))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitudeStart"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_START))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitudeStart"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_START))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.location"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskSetName"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.associatedArtifact"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_PROG_RUN.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.associatedArtifact"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.count"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COUNT))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_OS_ACCOUNT.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.userName"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.userId"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_ID))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_REMOTE_DRIVE.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.localPath"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCAL_PATH))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.remotePath"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_REMOTE_PATH))); + } else { + // This is the case that it is a custom type. The reason an else is + // necessary is to make sure that the source file column is added + for (BlackboardAttribute.Type type : attributeTypeSet) { + columns.add(new AttributeColumn(type.getDisplayName(), type)); + } + columns.add(new SourceFileColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile"))); + columns.add(new TaggedResultsColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags"))); + + // Short circuits to guarantee that the attribute types aren't added + // twice. + return columns; + } + // If it is an attribute column, it removes the attribute type of that + // column from the set, so types are not reported more than once. + for (Column column : columns) { + attributeTypeSet = column.removeTypeFromSet(attributeTypeSet); + } + // Now uses the remaining types in the set to construct columns + for (BlackboardAttribute.Type type : attributeTypeSet) { + columns.add(new AttributeColumn(type.getDisplayName(), type)); + } + // Source file column is added here for ordering purposes. + if (artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_RECENT_OBJECT.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_INSTALLED_PROG.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALENDAR_ENTRY.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_SPEED_DIAL_ENTRY.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_BOOKMARK.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_LAST_KNOWN_LOCATION.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_SEARCH.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_SERVICE_ACCOUNT.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_OS_INFO.getTypeID()) { + columns.add(new SourceFileColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile"))); + } + columns.add(new TaggedResultsColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags"))); + + return columns; + } + + /** + * Given a tsk_file's obj_id, return the unique path of that file. + * + * @param objId tsk_file obj_id + * + * @return String unique path + */ + private String getFileUniquePath(Content content) { + try { + if (content != null) { + return content.getUniquePath(); + } else { + return ""; + } + } catch (TskCoreException ex) { + errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetAbstractFileByID")); + logger.log(Level.WARNING, "Failed to get Abstract File by ID.", ex); //NON-NLS + } + return ""; + + } + + /** + * Get any tags associated with an artifact + * + * @param artifactId + * + * @return hash set of tag display names + * + * @throws SQLException + */ + @SuppressWarnings("deprecation") + private HashSet getUniqueTagNames(long artifactId) throws TskCoreException { + HashSet uniqueTagNames = new HashSet<>(); + + String query = "SELECT display_name, artifact_id FROM tag_names AS tn, blackboard_artifact_tags AS bat " + + //NON-NLS + "WHERE tn.tag_name_id = bat.tag_name_id AND bat.artifact_id = " + artifactId; //NON-NLS + + try (SleuthkitCase.CaseDbQuery dbQuery = Case.getCurrentCase().getSleuthkitCase().executeQuery(query)) { + ResultSet tagNameRows = dbQuery.getResultSet(); + while (tagNameRows.next()) { + uniqueTagNames.add(tagNameRows.getString("display_name")); //NON-NLS + } + } catch (TskCoreException | SQLException ex) { + throw new TskCoreException("Error getting tag names for artifact: ", ex); + } + + return uniqueTagNames; + + } + + private interface Column { + + String getColumnHeader(); + + String getCellData(ArtifactData artData); + + Set removeTypeFromSet(Set types); + } + + private class AttributeColumn implements Column { + + private final String columnHeader; + private final BlackboardAttribute.Type attributeType; + + /** + * Constructs an ArtifactCell + * + * @param columnHeader The header text of this column + * @param attributeType The attribute type associated with this column + */ + AttributeColumn(String columnHeader, BlackboardAttribute.Type attributeType) { + this.columnHeader = Objects.requireNonNull(columnHeader); + this.attributeType = attributeType; + } + + @Override + public String getColumnHeader() { + return this.columnHeader; + } + + @Override + public String getCellData(ArtifactData artData) { + List attributes = artData.getAttributes(); + for (BlackboardAttribute attribute : attributes) { + if (attribute.getAttributeType().equals(this.attributeType)) { + if (attribute.getAttributeType().getValueType() != BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME) { + return attribute.getDisplayString(); + } else { + return ContentUtils.getStringTime(attribute.getValueLong(), artData.getContent()); + } + } + } + return ""; + } + + @Override + public Set removeTypeFromSet(Set types) { + types.remove(this.attributeType); + return types; + } + } + + private class SourceFileColumn implements Column { + + private final String columnHeader; + + SourceFileColumn(String columnHeader) { + this.columnHeader = columnHeader; + } + + @Override + public String getColumnHeader() { + return this.columnHeader; + } + + @Override + public String getCellData(ArtifactData artData) { + return getFileUniquePath(artData.getContent()); + /*else if (this.columnHeader.equals(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags"))) { + return makeCommaSeparatedList(artData.getTags()); + } + return "";*/ + } + + @Override + public Set removeTypeFromSet(Set types) { + // This column doesn't have a type, so nothing to remove + return types; + } + } + + private class TaggedResultsColumn implements Column { + + private final String columnHeader; + + TaggedResultsColumn(String columnHeader) { + this.columnHeader = columnHeader; + } + + @Override + public String getColumnHeader() { + return this.columnHeader; + } + + @Override + public String getCellData(ArtifactData artData) { + return makeCommaSeparatedList(artData.getTags()); + } + + @Override + public Set removeTypeFromSet(Set types) { + // This column doesn't have a type, so nothing to remove + return types; + } + } + + private class HeaderOnlyColumn implements Column { + + private final String columnHeader; + + HeaderOnlyColumn(String columnHeader) { + this.columnHeader = columnHeader; + } + + @Override + public String getColumnHeader() { + return columnHeader; + } + + @Override + public String getCellData(ArtifactData artData) { + throw new UnsupportedOperationException("Cannot get cell data of unspecified column"); + } + + @Override + public Set removeTypeFromSet(Set types) { + // This column doesn't have a type, so nothing to remove + return types; + } + } +} From dbe2091f1843b5d90d5c034b09b921bf72542827 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Wed, 11 May 2016 15:35:30 -0400 Subject: [PATCH 009/172] Made report folder delete upon failure. --- .../modules/stix/STIXReportModule.java | 181 +++++++++--------- 1 file changed, 90 insertions(+), 91 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java b/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java index 2762f21e26..d583611952 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java @@ -18,48 +18,46 @@ */ package org.sleuthkit.autopsy.modules.stix; -import java.io.File; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.List; -import java.util.logging.Level; import java.io.BufferedWriter; +import java.io.File; import java.io.FileWriter; +import java.io.IOException; import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; import javax.swing.JPanel; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; import javax.xml.namespace.QName; - import org.mitre.cybox.cybox_2.ObjectType; import org.mitre.cybox.cybox_2.Observable; import org.mitre.cybox.cybox_2.ObservableCompositionType; +import org.mitre.cybox.cybox_2.OperatorTypeEnum; +import org.mitre.cybox.objects.AccountObjectType; +import org.mitre.cybox.objects.Address; +import org.mitre.cybox.objects.DomainName; +import org.mitre.cybox.objects.EmailMessage; +import org.mitre.cybox.objects.FileObjectType; +import org.mitre.cybox.objects.SystemObjectType; +import org.mitre.cybox.objects.URIObjectType; +import org.mitre.cybox.objects.URLHistory; +import org.mitre.cybox.objects.WindowsNetworkShare; +import org.mitre.cybox.objects.WindowsRegistryKey; import org.mitre.stix.common_1.IndicatorBaseType; import org.mitre.stix.indicator_2.Indicator; import org.mitre.stix.stix_1.STIXPackage; - -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.report.GeneralReportModule; import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.report.ReportProgressPanel; -import org.sleuthkit.datamodel.TskCoreException; - -import org.mitre.cybox.cybox_2.OperatorTypeEnum; -import org.mitre.cybox.objects.Address; -import org.mitre.cybox.objects.FileObjectType; -import org.mitre.cybox.objects.URIObjectType; -import org.mitre.cybox.objects.EmailMessage; -import org.mitre.cybox.objects.WindowsNetworkShare; -import org.mitre.cybox.objects.AccountObjectType; -import org.mitre.cybox.objects.SystemObjectType; -import org.mitre.cybox.objects.URLHistory; -import org.mitre.cybox.objects.DomainName; -import org.mitre.cybox.objects.WindowsRegistryKey; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.ModuleSettings; +import org.sleuthkit.autopsy.report.GeneralReportModule; +import org.sleuthkit.autopsy.report.ReportProgressPanel; import org.sleuthkit.autopsy.report.ReportProgressPanel.ReportStatus; +import org.sleuthkit.datamodel.TskCoreException; /** * @@ -79,8 +77,6 @@ public class STIXReportModule implements GeneralReportModule { private final boolean skipShortCircuit = true; - private BufferedWriter output = null; - // Hidden constructor for the report private STIXReportModule() { } @@ -111,27 +107,12 @@ public class STIXReportModule implements GeneralReportModule { reportAllResults = configPanel.getShowAllResults(); // Set up the output file - try { - File file = new File(reportPath); - output = new BufferedWriter(new FileWriter(file)); - } catch (IOException ex) { - logger.log(Level.SEVERE, String.format("Unable to open STIX report file %s", reportPath), ex); //NON-NLS - MessageNotifyUtil.Notify.show("STIXReportModule", //NON-NLS - NbBundle.getMessage(this.getClass(), - "STIXReportModule.notifyMsg.unableToOpenReportFile", - reportPath), - MessageNotifyUtil.MessageType.ERROR); - progressPanel.complete(ReportStatus.ERROR); - progressPanel.updateStatusLabel( - NbBundle.getMessage(this.getClass(), "STIXReportModule.progress.completedWithErrors")); - return; - } - // Keep track of whether any errors occur during processing boolean hadErrors = false; // Process the file/directory name entry String stixFileName = configPanel.getStixFile(); + File reportFile = new File(reportPath); if (stixFileName == null) { logger.log(Level.SEVERE, "STIXReportModuleConfigPanel.stixFile not initialized "); //NON-NLS MessageNotifyUtil.Message.error( @@ -139,6 +120,7 @@ public class STIXReportModule implements GeneralReportModule { progressPanel.complete(ReportStatus.ERROR); progressPanel.updateStatusLabel( NbBundle.getMessage(this.getClass(), "STIXReportModule.progress.noFildDirProvided")); + new File(baseReportDir).delete(); return; } if (stixFileName.isEmpty()) { @@ -148,6 +130,7 @@ public class STIXReportModule implements GeneralReportModule { progressPanel.complete(ReportStatus.ERROR); progressPanel.updateStatusLabel( NbBundle.getMessage(this.getClass(), "STIXReportModule.progress.noFildDirProvided")); + new File(baseReportDir).delete(); return; } File stixFile = new File(stixFileName); @@ -160,58 +143,74 @@ public class STIXReportModule implements GeneralReportModule { progressPanel.complete(ReportStatus.ERROR); progressPanel.updateStatusLabel( NbBundle.getMessage(this.getClass(), "STIXReportModule.progress.couldNotOpenFileDir", stixFileName)); + new File(baseReportDir).delete(); return; } + + try (BufferedWriter output = new BufferedWriter(new FileWriter(reportFile))) { + // Store the path + ModuleSettings.setConfigSetting("STIX", "defaultPath", stixFileName); //NON-NLS - // Store the path - ModuleSettings.setConfigSetting("STIX", "defaultPath", stixFileName); //NON-NLS - - // Create array of stix file(s) - File[] stixFiles; - if (stixFile.isFile()) { - stixFiles = new File[1]; - stixFiles[0] = stixFile; - } else { - stixFiles = stixFile.listFiles(); - } - - // Set the length of the progress bar - we increment twice for each file - progressPanel.setMaximumProgress(stixFiles.length * 2 + 1); - - // Process each STIX file - for (File file : stixFiles) { - try { - processFile(file.getAbsolutePath(), progressPanel); - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, String.format("Unable to process STIX file %s", file), ex); //NON-NLS - MessageNotifyUtil.Notify.show("STIXReportModule", //NON-NLS - ex.getLocalizedMessage(), - MessageNotifyUtil.MessageType.ERROR); - hadErrors = true; + // Create array of stix file(s) + File[] stixFiles; + if (stixFile.isFile()) { + stixFiles = new File[1]; + stixFiles[0] = stixFile; + } else { + stixFiles = stixFile.listFiles(); } - // Clear out the ID maps before loading the next file - idToObjectMap = new HashMap(); - idToResult = new HashMap(); - } + // Set the length of the progress bar - we increment twice for each file + progressPanel.setMaximumProgress(stixFiles.length * 2 + 1); - // Close the output file - if (output != null) { - try { - output.close(); - } catch (IOException ex) { - logger.log(Level.SEVERE, String.format("Error closing STIX report file %s", reportPath), ex); //NON-NLS + // Process each STIX file + for (File file : stixFiles) { + try { + processFile(file.getAbsolutePath(), progressPanel, output); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Unable to process STIX file %s", file), ex); //NON-NLS + MessageNotifyUtil.Notify.show("STIXReportModule", //NON-NLS + ex.getLocalizedMessage(), + MessageNotifyUtil.MessageType.ERROR); + hadErrors = true; + } + + // Clear out the ID maps before loading the next file + idToObjectMap = new HashMap(); + idToResult = new HashMap(); } - } - // Set the progress bar to done. If any errors occurred along the way, modify - // the "complete" message to indicate this. - if (hadErrors) { + // Close the output file + if (output != null) { + try { + output.close(); + } catch (IOException ex) { + logger.log(Level.SEVERE, String.format("Error closing STIX report file %s", reportPath), ex); //NON-NLS + } + } + + // Set the progress bar to done. If any errors occurred along the way, modify + // the "complete" message to indicate this. + if (hadErrors) { + progressPanel.complete(ReportStatus.ERROR); + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "STIXReportModule.progress.completedWithErrors")); + } else { + Case.getCurrentCase().addReport(reportPath, stixFileName, ""); + progressPanel.complete(ReportStatus.COMPLETE); + } + } catch (IOException ex) { + logger.log(Level.SEVERE, String.format("Unable to open STIX report file %s", reportPath), ex); //NON-NLS + MessageNotifyUtil.Notify.show("STIXReportModule", //NON-NLS + NbBundle.getMessage(this.getClass(), + "STIXReportModule.notifyMsg.unableToOpenReportFile", + reportPath), + MessageNotifyUtil.MessageType.ERROR); progressPanel.complete(ReportStatus.ERROR); progressPanel.updateStatusLabel( NbBundle.getMessage(this.getClass(), "STIXReportModule.progress.completedWithErrors")); - } else { - progressPanel.complete(ReportStatus.COMPLETE); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Unable to add report to database.", ex); } } @@ -223,14 +222,14 @@ public class STIXReportModule implements GeneralReportModule { * * @throws TskCoreException */ - private void processFile(String stixFile, ReportProgressPanel progressPanel) throws + private void processFile(String stixFile, ReportProgressPanel progressPanel, BufferedWriter output) throws TskCoreException { // Load the STIX file STIXPackage stix; stix = loadSTIXFile(stixFile); - printFileHeader(stixFile); + printFileHeader(stixFile, output); // Save any observables listed up front processObservables(stix); @@ -240,7 +239,7 @@ public class STIXReportModule implements GeneralReportModule { registryFileData = EvalRegistryObj.copyRegistryFiles(); // Process the indicators - processIndicators(stix); + processIndicators(stix, output); progressPanel.increment(); } @@ -292,7 +291,7 @@ public class STIXReportModule implements GeneralReportModule { * * @param stix STIXPackage */ - private void processIndicators(STIXPackage stix) throws TskCoreException { + private void processIndicators(STIXPackage stix, BufferedWriter output) throws TskCoreException { if (stix.getIndicators() != null) { List s = stix.getIndicators().getIndicators(); for (IndicatorBaseType t : s) { @@ -302,7 +301,7 @@ public class STIXReportModule implements GeneralReportModule { if (ind.getObservable().getObject() != null) { ObservableResult result = evaluateSingleObservable(ind.getObservable(), ""); if (result.isTrue() || reportAllResults) { - writeResultsToFile(ind, result.getDescription(), result.isTrue()); + writeResultsToFile(ind, result.getDescription(), result.isTrue(), output); } if (result.isTrue()) { saveResultsAsArtifacts(ind, result); @@ -311,7 +310,7 @@ public class STIXReportModule implements GeneralReportModule { ObservableResult result = evaluateObservableComposition(ind.getObservable().getObservableComposition(), " "); if (result.isTrue() || reportAllResults) { - writeResultsToFile(ind, result.getDescription(), result.isTrue()); + writeResultsToFile(ind, result.getDescription(), result.isTrue(), output); } if (result.isTrue()) { saveResultsAsArtifacts(ind, result); @@ -376,7 +375,7 @@ public class STIXReportModule implements GeneralReportModule { * @param resultStr - Full results for this indicator * @param found - true if the indicator was found in datasource(s) */ - private void writeResultsToFile(Indicator ind, String resultStr, boolean found) { + private void writeResultsToFile(Indicator ind, String resultStr, boolean found, BufferedWriter output) { if (output != null) { try { if (found) { @@ -412,7 +411,7 @@ public class STIXReportModule implements GeneralReportModule { * * @param a_fileName */ - private void printFileHeader(String a_fileName) { + private void printFileHeader(String a_fileName, BufferedWriter output) { if (output != null) { try { char[] chars = new char[a_fileName.length() + 8]; From 1b0168ba8890ce61943afdcc8379081bd97146ab Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Wed, 11 May 2016 15:36:20 -0400 Subject: [PATCH 010/172] Made report add to db properly. --- .../org/sleuthkit/autopsy/modules/stix/STIXReportModule.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java b/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java index d583611952..e971eadf25 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java @@ -146,7 +146,7 @@ public class STIXReportModule implements GeneralReportModule { new File(baseReportDir).delete(); return; } - + try (BufferedWriter output = new BufferedWriter(new FileWriter(reportFile))) { // Store the path ModuleSettings.setConfigSetting("STIX", "defaultPath", stixFileName); //NON-NLS @@ -191,12 +191,12 @@ public class STIXReportModule implements GeneralReportModule { // Set the progress bar to done. If any errors occurred along the way, modify // the "complete" message to indicate this. + Case.getCurrentCase().addReport(reportPath, stixFileName, ""); if (hadErrors) { progressPanel.complete(ReportStatus.ERROR); progressPanel.updateStatusLabel( NbBundle.getMessage(this.getClass(), "STIXReportModule.progress.completedWithErrors")); } else { - Case.getCurrentCase().addReport(reportPath, stixFileName, ""); progressPanel.complete(ReportStatus.COMPLETE); } } catch (IOException ex) { From d53637e7950e8b3638b902941379f6a875d1f793 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 12 May 2016 15:39:49 -0400 Subject: [PATCH 011/172] skeleton of new ListViewPane --- .../autopsy/timeline/VisualizationMode.java | 4 +- .../datamodel/FilteredEventsModel.java | 4 + .../autopsy/timeline/images/table.png | Bin 0 -> 920 bytes .../ui/AbstractVisualizationPane.java | 38 +++-- .../timeline/ui/VisualizationPanel.fxml | 12 ++ .../timeline/ui/VisualizationPanel.java | 9 ++ .../ui/countsview/CountsViewPane.java | 22 ++- .../ui/detailview/DetailViewPane.java | 20 +++ .../timeline/ui/detailview/DetailsChart.java | 28 ++-- .../timeline/ui/listvew/ListChart.java | 106 ++++++++++++++ .../timeline/ui/listvew/ListViewPane.java | 138 ++++++++++++++++++ 11 files changed, 351 insertions(+), 30 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/timeline/images/table.png create mode 100644 Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListChart.java create mode 100644 Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewPane.java diff --git a/Core/src/org/sleuthkit/autopsy/timeline/VisualizationMode.java b/Core/src/org/sleuthkit/autopsy/timeline/VisualizationMode.java index 8990b792bc..c624b1da9d 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/VisualizationMode.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/VisualizationMode.java @@ -23,5 +23,7 @@ package org.sleuthkit.autopsy.timeline; */ public enum VisualizationMode { - COUNTS, DETAIL; + COUNTS, + DETAIL, + LIST; } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/datamodel/FilteredEventsModel.java b/Core/src/org/sleuthkit/autopsy/timeline/datamodel/FilteredEventsModel.java index ad5bc8786e..b2b9136136 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/datamodel/FilteredEventsModel.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/datamodel/FilteredEventsModel.java @@ -288,6 +288,10 @@ public final class FilteredEventsModel { return repo.getEventIDs(overlap, intersect); } + public Set getEventIDs() { + return getEventIDs(requestedTimeRange.get(), requestedFilter.get()); + } + /** * return the number of events that pass the requested filter and are within * the given time range. diff --git a/Core/src/org/sleuthkit/autopsy/timeline/images/table.png b/Core/src/org/sleuthkit/autopsy/timeline/images/table.png new file mode 100644 index 0000000000000000000000000000000000000000..0d1e11a83410d46c6912689110b05a8e16eee606 GIT binary patch literal 920 zcmV;J184k+P)`(YZ2MPt(oFg$RqAXOr6{HS)~KtZIc zucWeB_fla+?&fR;-;e`YBve~MLWpuOLP8B~HPgD3A6iJIO0r=xzV4CCC*c^AQ2IUz zu_P7C*lbCvG~ABx-?g(<5|;5k+!&d($E6jPSsu^K+xN;p;L>C*Su_oyR zyn{IwR)!RROt#mjbBi1%YLcyMoQgnSIo%g0;qIH08=mK%%`I#RE^Cz}Y$~t=7n5oh z?A7q&;OOgptCF+pUCqipev`PpnsHbfD_`Gzb1=FZeTe(LEIsj~ update(); + public Pane getSpecificLabelPane() { + return specificLabelPane; + } + + public Pane getContextLabelPane() { + return contextLabelPane; + } + + public Region getSpacer() { + return spacer; + } + /** * The visualization nodes that are selected. * @@ -410,17 +419,17 @@ public abstract class AbstractVisualizationPane { - VBox vBox = new VBox(specificLabelPane, contextLabelPane); - vBox.setFillWidth(false); - HBox hBox = new HBox(spacer, vBox); - hBox.setFillHeight(false); - setBottom(hBox); - DoubleBinding spacerSize = getYAxis().widthProperty().add(getYAxis().tickLengthProperty()).add(getAxisMargin()); - spacer.minWidthProperty().bind(spacerSize); - spacer.prefWidthProperty().bind(spacerSize); - spacer.maxWidthProperty().bind(spacerSize); - }); +// Platform.runLater(() -> { +// VBox vBox = new VBox(specificLabelPane, contextLabelPane); +// vBox.setFillWidth(false); +// HBox hBox = new HBox(spacer, vBox); +// hBox.setFillHeight(false); +// setBottom(hBox); +// DoubleBinding spacerSize = getYAxis().widthProperty().add(getYAxis().tickLengthProperty()).add(getAxisMargin()); +// spacer.minWidthProperty().bind(spacerSize); +// spacer.prefWidthProperty().bind(spacerSize); +// spacer.maxWidthProperty().bind(spacerSize); +// }); createSeries(); @@ -693,7 +702,6 @@ public abstract class AbstractVisualizationPane + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java index 1ed89786db..bf5a37a0e7 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java @@ -85,6 +85,7 @@ import org.sleuthkit.autopsy.timeline.events.TagsUpdatedEvent; import org.sleuthkit.autopsy.timeline.ui.countsview.CountsViewPane; import org.sleuthkit.autopsy.timeline.ui.detailview.DetailViewPane; import org.sleuthkit.autopsy.timeline.ui.detailview.tree.EventsTree; +import org.sleuthkit.autopsy.timeline.ui.listvew.ListViewPane; import org.sleuthkit.autopsy.timeline.utils.RangeDivisionInfo; /** @@ -161,6 +162,8 @@ final public class VisualizationPanel extends BorderPane { @FXML private ToggleButton detailsToggle; @FXML + private ToggleButton listToggle; + @FXML private Button snapShotButton; @FXML private Button refreshButton; @@ -292,6 +295,8 @@ final public class VisualizationPanel extends BorderPane { controller.setViewMode(VisualizationMode.COUNTS); } else if (newValue == detailsToggle && oldValue != null) { controller.setViewMode(VisualizationMode.DETAIL); + } else if (newValue == listToggle && oldValue != null) { + controller.setViewMode(VisualizationMode.LIST); } }; @@ -551,6 +556,10 @@ final public class VisualizationPanel extends BorderPane { //make new visualization. switch (visMode) { + case LIST: + vizPane = new ListViewPane(controller); + Platform.runLater(() -> listToggle.setSelected(true)); + break; case COUNTS: vizPane = new CountsViewPane(controller); Platform.runLater(() -> countsToggle.setSelected(true)); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/CountsViewPane.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/CountsViewPane.java index 91649dcf37..75374caf23 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/CountsViewPane.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/CountsViewPane.java @@ -25,6 +25,7 @@ import java.util.function.Function; import javafx.application.Platform; import javafx.beans.Observable; import javafx.beans.binding.BooleanBinding; +import javafx.beans.binding.DoubleBinding; import javafx.beans.property.SimpleObjectProperty; import javafx.collections.FXCollections; import javafx.concurrent.Task; @@ -43,6 +44,7 @@ import javafx.scene.image.ImageView; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import javafx.scene.layout.Pane; +import javafx.scene.layout.VBox; import javafx.scene.text.Font; import javafx.scene.text.FontPosture; import javafx.scene.text.FontWeight; @@ -116,6 +118,18 @@ public class CountsViewPane extends AbstractVisualizationPane { + VBox vBox = new VBox(getSpecificLabelPane(), getContextLabelPane()); + vBox.setFillWidth(false); + HBox hBox = new HBox(getSpacer(), vBox); + hBox.setFillHeight(false); + setBottom(hBox); + DoubleBinding spacerSize = getYAxis().widthProperty().add(getYAxis().tickLengthProperty()).add(getAxisMargin()); + getSpacer().minWidthProperty().bind(spacerSize); + getSpacer().prefWidthProperty().bind(spacerSize); + getSpacer().maxWidthProperty().bind(spacerSize); + }); + setChart(new EventCountsChart(controller, dateAxis, countAxis, getSelectedNodes())); getChart().setData(dataSeries); Tooltip.install(getChart(), getDefaultTooltip()); @@ -220,7 +234,7 @@ public class CountsViewPane extends AbstractVisualizationPane { + VBox vBox = new VBox(getSpecificLabelPane(), getContextLabelPane()); + vBox.setFillWidth(false); + HBox hBox = new HBox(getSpacer(), vBox); + hBox.setFillHeight(false); + setBottom(hBox); + DoubleBinding spacerSize = getYAxis().widthProperty().add(getYAxis().tickLengthProperty()).add(getAxisMargin()); + getSpacer().minWidthProperty().bind(spacerSize); + getSpacer().prefWidthProperty().bind(spacerSize); + getSpacer().maxWidthProperty().bind(spacerSize); + }); + this.selectedEvents = new MappedList<>(getSelectedNodes(), EventNodeBase::getEvent); //initialize chart; @@ -416,5 +430,11 @@ public class DetailViewPane extends AbstractVisualizationPane { pinnedView = new ScrollingLaneWrapper(pinnedLane); pinnedLane.setMinHeight(MIN_PINNED_LANE_HEIGHT); - pinnedLane.maxVScrollProperty().addListener((Observable observable) -> syncPinnedHeight()); + pinnedLane.maxVScrollProperty().addListener(maxVSCrollProp -> syncPinnedHeight()); syncPinnedHeight(); //assemble scene graph @@ -427,17 +426,8 @@ final class DetailsChart extends Control implements TimeLineChart { configureMouseListeners(pinnedLane, mouseClickedHandler, chartDragHandler); //show and hide pinned lane in response to settings property change - getSkinnable().getLayoutSettings().pinnedLaneShowing().addListener(observable -> { - boolean selected = getSkinnable().getLayoutSettings().isPinnedLaneShowing(); - if (selected == false) { - dividerPosition = masterDetailPane.getDividerPosition(); - } - masterDetailPane.setShowDetailNode(selected); - if (selected) { - syncPinnedHeight(); - masterDetailPane.setDividerPosition(dividerPosition); - } - }); + getSkinnable().getLayoutSettings().pinnedLaneShowing().addListener(observable -> syncPinnedLaneShowing()); + syncPinnedLaneShowing(); //show and remove interval selector in sync with control state change getSkinnable().intervalSelector().addListener((observable, oldIntervalSelector, newIntervalSelector) -> { @@ -483,5 +473,17 @@ final class DetailsChart extends Control implements TimeLineChart { chartLane.setOnMouseClicked(chartDragHandler); chartLane.addEventHandler(MouseEvent.MOUSE_CLICKED, mouseClickedHandler); } + + private void syncPinnedLaneShowing() { + boolean selected = getSkinnable().getLayoutSettings().isPinnedLaneShowing(); + if (selected == false) { + dividerPosition = masterDetailPane.getDividerPosition(); + } + masterDetailPane.setShowDetailNode(selected); + if (selected) { + syncPinnedHeight(); + masterDetailPane.setDividerPosition(dividerPosition); + } + } } } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListChart.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListChart.java new file mode 100644 index 0000000000..6f95bb2efe --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListChart.java @@ -0,0 +1,106 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.timeline.ui.listvew; + +import java.util.Arrays; +import javafx.beans.property.SimpleObjectProperty; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.scene.Node; +import javafx.scene.chart.Axis; +import javafx.scene.control.ContextMenu; +import javafx.scene.control.TableCell; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TableView; +import javafx.scene.input.MouseEvent; +import org.sleuthkit.autopsy.timeline.TimeLineController; +import org.sleuthkit.autopsy.timeline.ui.IntervalSelector; +import org.sleuthkit.autopsy.timeline.ui.TimeLineChart; + +/** + * + */ +class ListChart extends TableView implements TimeLineChart { + + private final TimeLineController controller; + private final TableColumn idColumn = new TableColumn<>(); + private final TableColumn millisColumn = new TableColumn<>(); + + ListChart(TimeLineController controller) { + this.controller = controller; + getColumns().addAll(Arrays.asList(idColumn, millisColumn)); + + idColumn.setCellValueFactory(param -> new SimpleObjectProperty<>(param.getValue())); + millisColumn.setCellValueFactory(param -> { + return new SimpleObjectProperty<>(controller.getEventsModel().getEventById(param.getValue()).getStartMillis()); + }); + millisColumn.setCellFactory(col -> new TableCell() { + @Override + protected void updateItem(Long item, boolean empty) { + super.updateItem(item, empty); + + if (empty || item == null) { + setText(""); + } else { + setText(TimeLineController.getZonedFormatter().print(item)); + + } + } + }); + + millisColumn.setSortType(TableColumn.SortType.DESCENDING); + millisColumn.setSortable(true); + millisColumn.setComparator(Long::compare); + getSortOrder().setAll(Arrays.asList(millisColumn)); + + } + + @Override + public ObservableList getSelectedNodes() { + return FXCollections.observableArrayList(); + } + + @Override + public IntervalSelector getIntervalSelector() { + return null; + } + + @Override + public void setIntervalSelector(IntervalSelector newIntervalSelector) { +// throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public IntervalSelector newIntervalSelector() { + return null; + } + + @Override + public void clearIntervalSelector() { +// throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Axis getXAxis() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public TimeLineController getController() { + return controller; + } + + @Override + public void clearContextMenu() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public ContextMenu getContextMenu(MouseEvent m) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewPane.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewPane.java new file mode 100644 index 0000000000..60468f4952 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewPane.java @@ -0,0 +1,138 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.timeline.ui.listvew; + +import java.util.Set; +import javafx.concurrent.Task; +import javafx.scene.Node; +import javafx.scene.Parent; +import javafx.scene.chart.Axis; +import org.joda.time.Interval; +import org.sleuthkit.autopsy.timeline.TimeLineController; +import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel; +import org.sleuthkit.autopsy.timeline.datamodel.SingleEvent; +import org.sleuthkit.autopsy.timeline.ui.AbstractVisualizationPane; + +/** + * @param The type of data plotted along the x axis + * @param The type of data plotted along the y axis + * @param The type of nodes used to represent data items + * @param The type of the TimeLineChart this class uses to plot + * the data. Must extend Region. + * + * TODO: this is becoming (too?) closely tied to the notion that there is a + * XYChart doing the rendering. Is this a good idea? -jm + * + * TODO: pull up common history context menu items out of derived classes? -jm + * + * public abstract class AbstractVisualizationPane> extends BorderPane { + */ +public class ListViewPane extends AbstractVisualizationPane { + + /** + * Constructor + * + * @param controller + */ + public ListViewPane(TimeLineController controller) { + super(controller); + + //initialize chart; + setChart(new ListChart(controller)); + setSettingsNodes(new ListViewPane.ListViewSettingsPane().getChildrenUnmodifiable()); + } + + @Override + protected Boolean isTickBold(Long value) { + return true; + } + + @Override + protected void applySelectionEffect(Node node, Boolean applied) { +// throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + protected Task getNewUpdateTask() { + return new ListUpdateTask(); + } + + @Override + protected String getTickMarkLabel(Long tickValue) { + return ""; + } + + @Override + protected double getTickSpacing() { + return 0; + } + + @Override + protected Axis getXAxis() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + protected Axis getYAxis() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + protected double getAxisMargin() { + return 0; + } + + @Override + protected void clearChartData() { + getChart().getItems().clear(); + } + + private static class ListViewSettingsPane extends Parent { + + ListViewSettingsPane() { + } + } + + private class ListUpdateTask extends VisualizationUpdateTask { + + ListUpdateTask() { + super("List update task", true); + } + + @Override + protected Boolean call() throws Exception { + super.call(); //To change body of generated methods, choose Tools | Templates. + if (isCancelled()) { + return null; + } + FilteredEventsModel eventsModel = getEventsModel(); + + //clear the chart and set the horixontal axis + resetChart(eventsModel.getTimeRange()); + +// updateMessage(Bundle.DetailViewPane_loggedTask_queryDb()); + //get the event stripes to be displayed + Set eventIDs = eventsModel.getEventIDs(); + getChart().getItems().setAll(eventIDs); + +// updateMessage(Bundle.DetailViewPane_loggedTask_updateUI()); + return eventIDs.isEmpty() == false; + } + + @Override + protected void cancelled() { + super.cancelled(); + getController().retreat(); + } + + @Override + protected void setDateAxisValues(Interval timeRange) { +// detailsChartDateAxis.setRange(timeRange, true); +// pinnedDateAxis.setRange(timeRange, true); + } + } +} From 5678c0ca610337307ff6970530b2ddd6030daba2 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Fri, 13 May 2016 15:32:42 -0400 Subject: [PATCH 012/172] Fixed index artifact error messages. --- .../ExternalResultsImporter.java | 6 ++++-- .../android/BrowserLocationAnalyzer.java | 6 +++--- .../modules/android/CacheLocationAnalyzer.java | 8 ++++---- .../modules/android/CallLogAnalyzer.java | 11 ++++++----- .../modules/android/ContactAnalyzer.java | 7 ++++--- .../android/GoogleMapLocationAnalyzer.java | 7 ++++--- .../modules/android/TangoMessageAnalyzer.java | 8 +++++--- .../modules/android/TextMessageAnalyzer.java | 9 +++++---- .../modules/android/WWFMessageAnalyzer.java | 9 +++++---- .../SevenZipExtractor.java | 7 ++++--- .../exif/ExifParserFileIngestModule.java | 8 +++++--- .../FileExtMismatchIngestModule.java | 6 ++++-- .../hashdatabase/HashDbIngestModule.java | 14 ++++++++------ .../autopsy/modules/iOS/CallLogAnalyzer.java | 7 ++++--- .../autopsy/modules/iOS/ContactAnalyzer.java | 11 ++++++----- .../modules/iOS/TextMessageAnalyzer.java | 8 +++++--- .../FilesIdentifierIngestModule.java | 7 +++---- .../autopsy/modules/stix/StixArtifactData.java | 10 +++++----- .../autopsy/recentactivity/Extract.java | 12 ++++++------ .../ThunderbirdMboxFileIngestModule.java | 17 +++++++++-------- 20 files changed, 99 insertions(+), 79 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/externalresults/ExternalResultsImporter.java b/Core/src/org/sleuthkit/autopsy/externalresults/ExternalResultsImporter.java index 9deeb0e841..0b19827c48 100644 --- a/Core/src/org/sleuthkit/autopsy/externalresults/ExternalResultsImporter.java +++ b/Core/src/org/sleuthkit/autopsy/externalresults/ExternalResultsImporter.java @@ -27,6 +27,7 @@ import java.util.HashSet; import java.util.List; import java.util.logging.Level; import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.casemodule.services.FileManager; @@ -127,6 +128,7 @@ public final class ExternalResultsImporter { } } + @Messages({"ExternalResultsImporter.indexError.message=Failed to index imported artifact for keyword search."}) private void importArtifacts(ExternalResults results) { SleuthkitCase caseDb = Case.getCurrentCase().getSleuthkitCase(); for (ExternalResults.Artifact artifactData : results.getArtifacts()) { @@ -200,9 +202,9 @@ public final class ExternalResultsImporter { // index the artifact for keyword search blackboard.indexArtifact(artifact); } catch (Blackboard.BlackboardException ex) { - logger.log(Level.SEVERE, NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.error.msg", artifact.getDisplayName()), ex); //NON-NLS + logger.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getDisplayName(), ex); //NON-NLS MessageNotifyUtil.Notify.error( - NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.exception.msg"), artifact.getDisplayName()); + Bundle.ExternalResultsImporter_indexError_message(), artifact.getDisplayName()); } if (standardArtifactTypeIds.contains(artifactTypeId)) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/android/BrowserLocationAnalyzer.java b/Core/src/org/sleuthkit/autopsy/modules/android/BrowserLocationAnalyzer.java index d7f0543c49..5668721246 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/android/BrowserLocationAnalyzer.java +++ b/Core/src/org/sleuthkit/autopsy/modules/android/BrowserLocationAnalyzer.java @@ -26,7 +26,6 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.List; import java.util.logging.Level; - import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.Blackboard; @@ -72,6 +71,7 @@ class BrowserLocationAnalyzer { } } + @NbBundle.Messages({"BrowserLocationAnalyzer.indexError.message=Failed to index gps trackpoint artifact for keyword search."}) private static void findGeoLocationsInDB(String DatabasePath, AbstractFile f) { Connection connection = null; ResultSet resultSet = null; @@ -110,9 +110,9 @@ class BrowserLocationAnalyzer { // index the artifact for keyword search blackboard.indexArtifact(bba); } catch (Blackboard.BlackboardException ex) { - logger.log(Level.SEVERE, NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.error.msg", bba.getDisplayName()), ex); //NON-NLS + logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getDisplayName(), ex); //NON-NLS MessageNotifyUtil.Notify.error( - NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.exception.msg"), bba.getDisplayName()); + Bundle.BrowserLocationAnalyzer_indexError_message(), bba.getDisplayName()); } } } catch (Exception e) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/android/CacheLocationAnalyzer.java b/Core/src/org/sleuthkit/autopsy/modules/android/CacheLocationAnalyzer.java index 266bf09469..e1896a88d5 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/android/CacheLocationAnalyzer.java +++ b/Core/src/org/sleuthkit/autopsy/modules/android/CacheLocationAnalyzer.java @@ -25,8 +25,8 @@ import java.math.BigInteger; import java.nio.ByteBuffer; import java.util.List; import java.util.logging.Level; - import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.casemodule.services.FileManager; @@ -78,6 +78,7 @@ class CacheLocationAnalyzer { } } + @Messages({"CacheLocationAnalyzer.indexError.message=Failed to index gps trackpoint artifact for keyword search."}) private static void findGeoLocationsInFile(File file, AbstractFile f) { byte[] bytes; // will temporarily hold bytes to be converted into the correct data types @@ -140,14 +141,13 @@ class CacheLocationAnalyzer { //Not storing these for now. // bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_VALUE.getTypeID(),moduleName, accuracy)); // bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID(),moduleName, confidence)); - try { // index the artifact for keyword search blackboard.indexArtifact(bba); } catch (Blackboard.BlackboardException ex) { - logger.log(Level.SEVERE, NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.error.msg", bba.getDisplayName()), ex); //NON-NLS + logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getDisplayName(), ex); //NON-NLS MessageNotifyUtil.Notify.error( - NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.exception.msg"), bba.getDisplayName()); + Bundle.CacheLocationAnalyzer_indexError_message(), bba.getDisplayName()); } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/android/CallLogAnalyzer.java b/Core/src/org/sleuthkit/autopsy/modules/android/CallLogAnalyzer.java index 7df25e15ff..62594572eb 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/android/CallLogAnalyzer.java +++ b/Core/src/org/sleuthkit/autopsy/modules/android/CallLogAnalyzer.java @@ -28,7 +28,7 @@ import java.sql.Statement; import java.util.Arrays; import java.util.List; import java.util.logging.Level; -import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.casemodule.services.FileManager; @@ -58,7 +58,7 @@ class CallLogAnalyzer { private static final Iterable tableNames = Arrays.asList("calls", "logs"); //NON-NLS public static void findCallLogs(Content dataSource, FileManager fileManager) { - blackboard = Case.getCurrentCase().getServices().getBlackboard(); + blackboard = Case.getCurrentCase().getServices().getBlackboard(); try { List absFiles = fileManager.findFiles(dataSource, "logs.db"); //NON-NLS absFiles.addAll(fileManager.findFiles(dataSource, "contacts.db")); //NON-NLS @@ -77,6 +77,7 @@ class CallLogAnalyzer { } } + @Messages({"CallLogAnalyzer.indexError.message=Failed to index call log artifact for keyword search."}) private static void findCallLogsInDB(String DatabasePath, AbstractFile f) { if (DatabasePath == null || DatabasePath.isEmpty()) { @@ -113,16 +114,16 @@ class CallLogAnalyzer { // index the artifact for keyword search blackboard.indexArtifact(bba); } catch (Blackboard.BlackboardException ex) { - logger.log(Level.SEVERE, NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.error.msg", bba.getDisplayName()), ex); //NON-NLS + logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getDisplayName(), ex); //NON-NLS MessageNotifyUtil.Notify.error( - NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.exception.msg"), bba.getDisplayName()); + Bundle.CallLogAnalyzer_indexError_message(), bba.getDisplayName()); } } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error posting call log record to the Blackboard", ex); //NON-NLS } } } catch (SQLException e) { - logger.log(Level.WARNING, "Could not read table {0} in db {1}", new Object[]{tableName, DatabasePath}); //NON-NLS + logger.log(Level.WARNING, String.format("Could not read table %s in db %s", tableName, DatabasePath), e); //NON-NLS } } } catch (SQLException e) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/android/ContactAnalyzer.java b/Core/src/org/sleuthkit/autopsy/modules/android/ContactAnalyzer.java index 25affa740f..cff91bf689 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/android/ContactAnalyzer.java +++ b/Core/src/org/sleuthkit/autopsy/modules/android/ContactAnalyzer.java @@ -27,7 +27,7 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.List; import java.util.logging.Level; -import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.casemodule.services.FileManager; @@ -79,6 +79,7 @@ class ContactAnalyzer { * path The fileId will be the Abstract file associated * with the artifacts */ + @Messages({"ContactAnalyzer.indexError.message=Failed to index contact artifact for keyword search."}) private static void findContactsInDB(String databasePath, AbstractFile f) { Connection connection = null; ResultSet resultSet = null; @@ -154,9 +155,9 @@ class ContactAnalyzer { // index the artifact for keyword search blackboard.indexArtifact(bba); } catch (Blackboard.BlackboardException ex) { - logger.log(Level.SEVERE, NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.error.msg", bba.getDisplayName()), ex); //NON-NLS + logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getDisplayName(), ex); //NON-NLS MessageNotifyUtil.Notify.error( - NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.exception.msg"), bba.getDisplayName()); + Bundle.ContactAnalyzer_indexError_message(), bba.getDisplayName()); } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/android/GoogleMapLocationAnalyzer.java b/Core/src/org/sleuthkit/autopsy/modules/android/GoogleMapLocationAnalyzer.java index d7889257dc..a073800354 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/android/GoogleMapLocationAnalyzer.java +++ b/Core/src/org/sleuthkit/autopsy/modules/android/GoogleMapLocationAnalyzer.java @@ -26,8 +26,8 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.List; import java.util.logging.Level; - import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.casemodule.services.FileManager; @@ -71,6 +71,7 @@ class GoogleMapLocationAnalyzer { } } + @Messages({"GoogleMapLocationAnalyzer.indexError.message=Failed to index gps route artifact for keyword search."}) private static void findGeoLocationsInDB(String DatabasePath, AbstractFile f) { Connection connection = null; ResultSet resultSet = null; @@ -136,9 +137,9 @@ class GoogleMapLocationAnalyzer { // index the artifact for keyword search blackboard.indexArtifact(bba); } catch (Blackboard.BlackboardException ex) { - logger.log(Level.SEVERE, NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.error.msg", bba.getDisplayName()), ex); //NON-NLS + logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getDisplayName(), ex); //NON-NLS MessageNotifyUtil.Notify.error( - NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.exception.msg"), bba.getDisplayName()); + Bundle.GoogleMapLocationAnalyzer_indexError_message(), bba.getDisplayName()); } } } catch (Exception e) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/android/TangoMessageAnalyzer.java b/Core/src/org/sleuthkit/autopsy/modules/android/TangoMessageAnalyzer.java index 09dba30821..c8decb163e 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/android/TangoMessageAnalyzer.java +++ b/Core/src/org/sleuthkit/autopsy/modules/android/TangoMessageAnalyzer.java @@ -28,6 +28,7 @@ import java.util.List; import java.util.logging.Level; import org.apache.commons.codec.binary.Base64; import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.casemodule.services.FileManager; @@ -68,6 +69,7 @@ class TangoMessageAnalyzer { } } + @Messages({"TangoMessageAnalyzer.indexError.message=Failed to index message artifact for keyword search."}) private static void findTangoMessagesInDB(String DatabasePath, AbstractFile f) { Connection connection = null; ResultSet resultSet = null; @@ -110,14 +112,14 @@ class TangoMessageAnalyzer { bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, moduleName, NbBundle.getMessage(TangoMessageAnalyzer.class, "TangoMessageAnalyzer.bbAttribute.tangoMessage"))); - + try { // index the artifact for keyword search blackboard.indexArtifact(bba); } catch (Blackboard.BlackboardException ex) { - logger.log(Level.SEVERE, NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.error.msg", bba.getDisplayName()), ex); //NON-NLS MessageNotifyUtil.Notify.error( - NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.exception.msg"), bba.getDisplayName()); + Bundle.TangoMessageAnalyzer_indexError_message(), bba.getDisplayName()); + logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getDisplayName(), ex); //NON-NLS } } } catch (Exception e) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/android/TextMessageAnalyzer.java b/Core/src/org/sleuthkit/autopsy/modules/android/TextMessageAnalyzer.java index edf12e0b66..bb6f4d0896 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/android/TextMessageAnalyzer.java +++ b/Core/src/org/sleuthkit/autopsy/modules/android/TextMessageAnalyzer.java @@ -26,8 +26,8 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.List; import java.util.logging.Level; - import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.casemodule.services.FileManager; @@ -68,6 +68,7 @@ class TextMessageAnalyzer { } } + @Messages({"TextMessageAnalyzer.indexError.message=Failed to index message artifact for keyword search."}) private static void findTextsInDB(String DatabasePath, AbstractFile f) { Connection connection = null; ResultSet resultSet = null; @@ -123,14 +124,14 @@ class TextMessageAnalyzer { bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, moduleName, NbBundle.getMessage(TextMessageAnalyzer.class, "TextMessageAnalyzer.bbAttribute.smsMessage"))); - + try { // index the artifact for keyword search blackboard.indexArtifact(bba); } catch (Blackboard.BlackboardException ex) { - logger.log(Level.SEVERE, NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.error.msg", bba.getDisplayName()), ex); //NON-NLS + logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getDisplayName(), ex); //NON-NLS MessageNotifyUtil.Notify.error( - NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.exception.msg"), bba.getDisplayName()); + Bundle.TextMessageAnalyzer_indexError_message(), bba.getDisplayName()); } } } catch (Exception e) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/android/WWFMessageAnalyzer.java b/Core/src/org/sleuthkit/autopsy/modules/android/WWFMessageAnalyzer.java index 87bbd8dc4d..33a3b2b186 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/android/WWFMessageAnalyzer.java +++ b/Core/src/org/sleuthkit/autopsy/modules/android/WWFMessageAnalyzer.java @@ -26,8 +26,8 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.List; import java.util.logging.Level; - import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.casemodule.services.FileManager; @@ -71,6 +71,7 @@ class WWFMessageAnalyzer { } } + @Messages({"WWFMessageAnalyzer.indexError.message=Failed to index message artifact for keyword search."}) private static void findWWFMessagesInDB(String DatabasePath, AbstractFile f) { Connection connection = null; ResultSet resultSet = null; @@ -110,14 +111,14 @@ class WWFMessageAnalyzer { bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, moduleName, NbBundle.getMessage(WWFMessageAnalyzer.class, "WWFMessageAnalyzer.bbAttribute.wordsWithFriendsMsg"))); - + try { // index the artifact for keyword search blackboard.indexArtifact(bba); } catch (Blackboard.BlackboardException ex) { - logger.log(Level.SEVERE, NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.error.msg", bba.getDisplayName()), ex); //NON-NLS + logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getDisplayName(), ex); //NON-NLS MessageNotifyUtil.Notify.error( - NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.exception.msg"), bba.getDisplayName()); + Bundle.WWFMessageAnalyzer_indexError_message(), bba.getDisplayName()); } } } catch (Exception e) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java index 8e25feaa23..47a38d6a7d 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java @@ -42,6 +42,7 @@ import net.sf.sevenzipjbinding.simple.ISimpleInArchive; import net.sf.sevenzipjbinding.simple.ISimpleInArchiveItem; import org.netbeans.api.progress.ProgressHandle; import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.casemodule.services.FileManager; @@ -50,7 +51,6 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.ingest.IngestJobContext; import org.sleuthkit.autopsy.ingest.IngestMessage; -import org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException; import org.sleuthkit.autopsy.ingest.IngestMonitor; import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.autopsy.ingest.ModuleContentEvent; @@ -267,6 +267,7 @@ class SevenZipExtractor { * * @return list of unpacked derived files */ + @Messages({"SevenZipExtractor.indexError.message=Failed to index encription detected artifact for keyword search."}) void unpack(AbstractFile archiveFile) { blackboard = Case.getCurrentCase().getServices().getBlackboard(); String archiveFilePath; @@ -586,9 +587,9 @@ class SevenZipExtractor { // index the artifact for keyword search blackboard.indexArtifact(artifact); } catch (Blackboard.BlackboardException ex) { - logger.log(Level.SEVERE, NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.error.msg", artifact.getDisplayName()), ex); //NON-NLS + logger.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getDisplayName(), ex); //NON-NLS MessageNotifyUtil.Notify.error( - NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.exception.msg"), artifact.getDisplayName()); + Bundle.SevenZipExtractor_indexError_message(), artifact.getDisplayName()); } services.fireModuleDataEvent(new ModuleDataEvent(EmbeddedFileExtractorModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED)); diff --git a/Core/src/org/sleuthkit/autopsy/modules/exif/ExifParserFileIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/exif/ExifParserFileIngestModule.java index 2534d376f7..3d30bc0972 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/exif/ExifParserFileIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/exif/ExifParserFileIngestModule.java @@ -38,15 +38,16 @@ import java.util.TimeZone; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.ingest.FileIngestModule; import org.sleuthkit.autopsy.ingest.IngestJobContext; +import org.sleuthkit.autopsy.ingest.IngestModuleReferenceCounter; import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; -import org.sleuthkit.autopsy.ingest.IngestModuleReferenceCounter; import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -133,6 +134,7 @@ public final class ExifParserFileIngestModule implements FileIngestModule { return processFile(content); } + @Messages({"ExifParserFileIngestModule.indexError.message=Failed to index Exif Metadata artifact for keyword search."}) ProcessResult processFile(AbstractFile f) { InputStream in = null; BufferedInputStream bin = null; @@ -206,9 +208,9 @@ public final class ExifParserFileIngestModule implements FileIngestModule { // index the artifact for keyword search blackboard.indexArtifact(bba); } catch (Blackboard.BlackboardException ex) { - logger.log(Level.SEVERE, NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.error.msg", bba.getDisplayName()), ex); //NON-NLS + logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getDisplayName(), ex); //NON-NLS MessageNotifyUtil.Notify.error( - NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.exception.msg"), bba.getDisplayName()); + Bundle.ExifParserFileIngestModule_indexError_message(), bba.getDisplayName()); } filesToFire = true; } diff --git a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchIngestModule.java index 6f9a9ea98c..827b75ae49 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchIngestModule.java @@ -23,6 +23,7 @@ import java.util.HashMap; import java.util.Set; import java.util.logging.Level; import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.coreutils.Logger; @@ -105,6 +106,7 @@ public class FileExtMismatchIngestModule implements FileIngestModule { } @Override + @Messages({"FileExtMismatchIngestModule.indexError.message=Failed to index extension mismatch artifact for keyword search."}) public ProcessResult process(AbstractFile abstractFile) { blackboard = Case.getCurrentCase().getServices().getBlackboard(); if (this.settings.skipKnownFiles() && (abstractFile.getKnown() == FileKnown.KNOWN)) { @@ -139,9 +141,9 @@ public class FileExtMismatchIngestModule implements FileIngestModule { // index the artifact for keyword search blackboard.indexArtifact(bart); } catch (Blackboard.BlackboardException ex) { - logger.log(Level.SEVERE, NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.error.msg", bart.getDisplayName()), ex); //NON-NLS + logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bart.getDisplayName(), ex); //NON-NLS MessageNotifyUtil.Notify.error( - NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.exception.msg"), bart.getDisplayName()); + Bundle.FileExtMismatchIngestModule_indexError_message(), bart.getDisplayName()); } services.fireModuleDataEvent(new ModuleDataEvent(FileExtMismatchDetectorModuleFactory.getModuleName(), ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED, Collections.singletonList(bart))); diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java index 0199727cb2..97317734b3 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java @@ -26,27 +26,28 @@ import java.util.List; import java.util.concurrent.atomic.AtomicLong; import java.util.logging.Level; import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.ingest.FileIngestModule; import org.sleuthkit.autopsy.ingest.IngestMessage; +import org.sleuthkit.autopsy.ingest.IngestModuleReferenceCounter; import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; +import org.sleuthkit.datamodel.HashHitInfo; import org.sleuthkit.datamodel.HashUtility; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskException; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; -import org.sleuthkit.autopsy.ingest.FileIngestModule; -import org.sleuthkit.autopsy.ingest.IngestModuleReferenceCounter; -import org.sleuthkit.datamodel.HashHitInfo; @NbBundle.Messages({ "HashDbIngestModule.noKnownBadHashDbSetMsg=No known bad hash database set.", @@ -285,6 +286,7 @@ public class HashDbIngestModule implements FileIngestModule { return ret; } + @Messages({"HashDbIngestModule.indexError.message=Failed to index hashset hit artifact for keyword search."}) private void postHashSetHitToBlackboard(AbstractFile abstractFile, String md5Hash, String hashSetName, String comment, boolean showInboxMessage) { try { String MODULE_NAME = NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.moduleName"); @@ -303,9 +305,9 @@ public class HashDbIngestModule implements FileIngestModule { // index the artifact for keyword search blackboard.indexArtifact(badFile); } catch (Blackboard.BlackboardException ex) { - logger.log(Level.SEVERE, NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.error.msg", badFile.getDisplayName()), ex); //NON-NLS + logger.log(Level.SEVERE, "Unable to index blackboard artifact " + badFile.getDisplayName(), ex); //NON-NLS MessageNotifyUtil.Notify.error( - NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.exception.msg"), badFile.getDisplayName()); + Bundle.HashDbIngestModule_indexError_message(), badFile.getDisplayName()); } if (showInboxMessage) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/iOS/CallLogAnalyzer.java b/Core/src/org/sleuthkit/autopsy/modules/iOS/CallLogAnalyzer.java index 22ca91c064..00858550f3 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/iOS/CallLogAnalyzer.java +++ b/Core/src/org/sleuthkit/autopsy/modules/iOS/CallLogAnalyzer.java @@ -25,7 +25,7 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.List; import java.util.logging.Level; -import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.coreutils.Logger; @@ -74,6 +74,7 @@ class CallLogAnalyzer { } } + @Messages({"CallLogAnalyzer.indexError.message=Failed to index call log artifact for keyword search."}) private void findCallLogsInDB(String DatabasePath, long fId) { if (DatabasePath == null || DatabasePath.isEmpty()) { return; @@ -128,9 +129,9 @@ class CallLogAnalyzer { // index the artifact for keyword search blackboard.indexArtifact(bba); } catch (Blackboard.BlackboardException ex) { - logger.log(Level.SEVERE, NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.error.msg", bba.getDisplayName()), ex); //NON-NLS + logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getDisplayName(), ex); //NON-NLS MessageNotifyUtil.Notify.error( - NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.exception.msg"), bba.getDisplayName()); + Bundle.CallLogAnalyzer_indexError_message(), bba.getDisplayName()); } } } catch (Exception e) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/iOS/ContactAnalyzer.java b/Core/src/org/sleuthkit/autopsy/modules/iOS/ContactAnalyzer.java index 7c63e28a8d..fbfdaf18b4 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/iOS/ContactAnalyzer.java +++ b/Core/src/org/sleuthkit/autopsy/modules/iOS/ContactAnalyzer.java @@ -30,18 +30,18 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.List; import java.util.logging.Level; -import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; +import org.sleuthkit.datamodel.ReadContentInputStream; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.datamodel.ContentUtils; -import org.sleuthkit.datamodel.ReadContentInputStream; class ContactAnalyzer { @@ -91,6 +91,7 @@ class ContactAnalyzer { * path The fileId will be the Abstract file associated * with the artifacts */ + @Messages({"ContactAnalyzer.indexError.message=Failed to index contact artifact for keyword search."}) private void findContactsInDB(String DatabasePath, long fId) { if (DatabasePath == null || DatabasePath.isEmpty()) { return; @@ -149,9 +150,9 @@ class ContactAnalyzer { // index the artifact for keyword search blackboard.indexArtifact(bba); } catch (Blackboard.BlackboardException ex) { - logger.log(Level.SEVERE, NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.error.msg", bba.getDisplayName()), ex); //NON-NLS + logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getDisplayName(), ex); //NON-NLS MessageNotifyUtil.Notify.error( - NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.exception.msg"), bba.getDisplayName()); + Bundle.ContactAnalyzer_indexError_message(), bba.getDisplayName()); } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/iOS/TextMessageAnalyzer.java b/Core/src/org/sleuthkit/autopsy/modules/iOS/TextMessageAnalyzer.java index 44c08ae0cf..1cbe6a2e2b 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/iOS/TextMessageAnalyzer.java +++ b/Core/src/org/sleuthkit/autopsy/modules/iOS/TextMessageAnalyzer.java @@ -26,6 +26,7 @@ import java.sql.Statement; import java.util.List; import java.util.logging.Level; import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.coreutils.Logger; @@ -74,6 +75,7 @@ class TextMessageAnalyzer { } } + @Messages({"TextMessageAnalyzer.indexError.message=Failed to index message artifact for keyword search."}) private void findTextsInDB(String DatabasePath, long fId) { if (DatabasePath == null || DatabasePath.isEmpty()) { return; @@ -127,14 +129,14 @@ class TextMessageAnalyzer { bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT, moduleName, subject)); bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT, moduleName, body)); bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, moduleName, NbBundle.getMessage(this.getClass(), "TextMessageAnalyzer.bbAttribute.smsMessage"))); - + try { // index the artifact for keyword search blackboard.indexArtifact(bba); } catch (Blackboard.BlackboardException ex) { - logger.log(Level.SEVERE, NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.error.msg", bba.getDisplayName()), ex); //NON-NLS + logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getDisplayName(), ex); //NON-NLS MessageNotifyUtil.Notify.error( - NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.exception.msg"), bba.getDisplayName()); + Bundle.TextMessageAnalyzer_indexError_message(), bba.getDisplayName()); } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesIdentifierIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesIdentifierIngestModule.java index 62b423015b..dd389b90fb 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesIdentifierIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesIdentifierIngestModule.java @@ -24,7 +24,6 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; @@ -100,6 +99,7 @@ final class FilesIdentifierIngestModule implements FileIngestModule { * @inheritDoc */ @Override + @Messages({"FilesIdentifierIngestModule.indexError.message=Failed to index interesting file hit artifact for keyword search."}) public ProcessResult process(AbstractFile file) { blackboard = Case.getCurrentCase().getServices().getBlackboard(); @@ -131,9 +131,8 @@ final class FilesIdentifierIngestModule implements FileIngestModule { // index the artifact for keyword search blackboard.indexArtifact(artifact); } catch (Blackboard.BlackboardException ex) { - logger.log(Level.SEVERE, NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.error.msg", artifact.getDisplayName()), ex); //NON-NLS - MessageNotifyUtil.Notify.error( - NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.exception.msg"), artifact.getDisplayName()); + logger.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getDisplayName(), ex); //NON-NLS + MessageNotifyUtil.Notify.error(Bundle.FilesIdentifierIngestModule_indexError_message(), artifact.getDisplayName()); } IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent(moduleName, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, Collections.singletonList(artifact))); diff --git a/Core/src/org/sleuthkit/autopsy/modules/stix/StixArtifactData.java b/Core/src/org/sleuthkit/autopsy/modules/stix/StixArtifactData.java index 9a19e4cedf..d2440e8861 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/stix/StixArtifactData.java +++ b/Core/src/org/sleuthkit/autopsy/modules/stix/StixArtifactData.java @@ -19,7 +19,7 @@ package org.sleuthkit.autopsy.modules.stix; import java.util.logging.Level; -import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.coreutils.Logger; @@ -58,6 +58,7 @@ class StixArtifactData { objType = a_objType; } + @Messages({"StixArtifactData.indexError.message=Failed to index interesting file hit artifact for keyword search."}) public void createArtifact(String a_title) throws TskCoreException { Blackboard blackboard = Case.getCurrentCase().getServices().getBlackboard(); @@ -72,14 +73,13 @@ class StixArtifactData { bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, "Stix", setName)); //NON-NLS bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TITLE, "Stix", observableId)); //NON-NLS bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, "Stix", objType)); //NON-NLS - + try { // index the artifact for keyword search blackboard.indexArtifact(bba); } catch (Blackboard.BlackboardException ex) { - logger.log(Level.SEVERE, NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.error.msg", bba.getDisplayName()), ex); //NON-NLS - MessageNotifyUtil.Notify.error( - NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.exception.msg"), bba.getDisplayName()); + logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getDisplayName(), ex); //NON-NLS + MessageNotifyUtil.Notify.error(Bundle.StixArtifactData_indexError_message(), bba.getDisplayName()); } } diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Extract.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Extract.java index 1bf8eecb5c..0c2c2e1ffb 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Extract.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Extract.java @@ -22,18 +22,18 @@ */ package org.sleuthkit.autopsy.recentactivity; -import org.sleuthkit.autopsy.coreutils.SQLiteDBConnect; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.*; import java.util.logging.Level; - import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.coreutils.Logger; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.Blackboard; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.coreutils.SQLiteDBConnect; import org.sleuthkit.autopsy.ingest.IngestJobContext; import org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException; import org.sleuthkit.datamodel.*; @@ -103,15 +103,15 @@ abstract class Extract { * * @param bbart Blackboard artifact to be indexed */ + @Messages({"Extract.indexError.message=Failed to index artifact for keyword search."}) void indexArtifact(BlackboardArtifact bbart) { Blackboard blackboard = Case.getCurrentCase().getServices().getBlackboard(); try { // index the artifact for keyword search blackboard.indexArtifact(bbart); } catch (Blackboard.BlackboardException ex) { - logger.log(Level.SEVERE, NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.error.msg", bbart.getDisplayName()), ex); //NON-NLS - MessageNotifyUtil.Notify.error( - NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.exception.msg"), bbart.getDisplayName()); + logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bbart.getDisplayName(), ex); //NON-NLS + MessageNotifyUtil.Notify.error(Bundle.Extract_indexError_message(), bbart.getDisplayName()); } } diff --git a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/ThunderbirdMboxFileIngestModule.java b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/ThunderbirdMboxFileIngestModule.java index 3df364b32e..663aa01999 100644 --- a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/ThunderbirdMboxFileIngestModule.java +++ b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/ThunderbirdMboxFileIngestModule.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.casemodule.services.FileManager; @@ -73,7 +74,7 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule { public ProcessResult process(AbstractFile abstractFile) { blackboard = Case.getCurrentCase().getServices().getBlackboard(); - + // skip known if (abstractFile.getKnown().equals(TskData.FileKnown.KNOWN)) { return ProcessResult.OK; @@ -120,6 +121,7 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule { * * @return */ + @Messages({"ThunderbirdMboxFileIngestModule.processPst.indexError.message=Failed to index encryption detected artifact for keyword search."}) private ProcessResult processPst(AbstractFile abstractFile) { String fileName = getTempPath() + File.separator + abstractFile.getName() + "-" + String.valueOf(abstractFile.getId()); @@ -159,11 +161,10 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule { // index the artifact for keyword search blackboard.indexArtifact(artifact); } catch (Blackboard.BlackboardException ex) { - logger.log(Level.SEVERE, NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.error.msg", artifact.getDisplayName()), ex); //NON-NLS - MessageNotifyUtil.Notify.error( - NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.exception.msg"), artifact.getDisplayName()); + MessageNotifyUtil.Notify.error(Bundle.ThunderbirdMboxFileIngestModule_processPst_indexError_message(), artifact.getDisplayName()); + logger.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getDisplayName(), ex); //NON-NLS } - + services.fireModuleDataEvent(new ModuleDataEvent(EmailParserModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED)); } catch (TskCoreException ex) { logger.log(Level.INFO, "Failed to add encryption attribute to file: {0}", abstractFile.getName()); //NON-NLS @@ -354,6 +355,7 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule { * @param email * @param abstractFile */ + @Messages({"ThunderbirdMboxFileIngestModule.addArtifact.indexError.message=Failed to index email message detected artifact for keyword search."}) private void addArtifact(EmailMessage email, AbstractFile abstractFile) { List bbattributes = new ArrayList<>(); String to = email.getRecipients(); @@ -413,9 +415,8 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule { // index the artifact for keyword search blackboard.indexArtifact(bbart); } catch (Blackboard.BlackboardException ex) { - logger.log(Level.SEVERE, NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.error.msg", bbart.getDisplayName()), ex); //NON-NLS - MessageNotifyUtil.Notify.error( - NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.exception.msg"), bbart.getDisplayName()); + logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bbart.getDisplayName(), ex); //NON-NLS + MessageNotifyUtil.Notify.error(Bundle.ThunderbirdMboxFileIngestModule_addArtifact_indexError_message(), bbart.getDisplayName()); } } catch (TskCoreException ex) { logger.log(Level.WARNING, null, ex); From 2858421d46a35031158b7de7b60b56f05d314db2 Mon Sep 17 00:00:00 2001 From: jmillman Date: Fri, 13 May 2016 16:57:33 -0400 Subject: [PATCH 013/172] flesh out ListViewPane, keep events sorted by date --- .../datamodel/FilteredEventsModel.java | 4 +- .../autopsy/timeline/db/EventDB.java | 10 +- .../autopsy/timeline/db/EventsRepository.java | 2 +- .../timeline/ui/VisualizationPanel.java | 37 ++-- .../timeline/ui/listvew/ListChart.java | 163 +++++++++++++++--- .../timeline/ui/listvew/ListViewPane.java | 4 +- 6 files changed, 163 insertions(+), 57 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/timeline/datamodel/FilteredEventsModel.java b/Core/src/org/sleuthkit/autopsy/timeline/datamodel/FilteredEventsModel.java index 8917c0cb84..8a744a5e20 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/datamodel/FilteredEventsModel.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/datamodel/FilteredEventsModel.java @@ -279,7 +279,7 @@ public final class FilteredEventsModel { return repo.getTagCountsByTagName(eventIDsWithTags); } - public Set getEventIDs(Interval timeRange, Filter filter) { + public List getEventIDs(Interval timeRange, Filter filter) { final Interval overlap; final RootFilter intersect; synchronized (this) { @@ -290,7 +290,7 @@ public final class FilteredEventsModel { return repo.getEventIDs(overlap, intersect); } - public Set getEventIDs() { + public List getEventIDs() { return getEventIDs(requestedTimeRange.get(), requestedFilter.get()); } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/db/EventDB.java b/Core/src/org/sleuthkit/autopsy/timeline/db/EventDB.java index 996c35ef3b..2374e7a032 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/db/EventDB.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/db/EventDB.java @@ -343,18 +343,19 @@ public class EventDB { return result; } - Set getEventIDs(Interval timeRange, RootFilter filter) { + List getEventIDs(Interval timeRange, RootFilter filter) { return getEventIDs(timeRange.getStartMillis() / 1000, timeRange.getEndMillis() / 1000, filter); } - Set getEventIDs(Long startTime, Long endTime, RootFilter filter) { + List getEventIDs(Long startTime, Long endTime, RootFilter filter) { if (Objects.equals(startTime, endTime)) { endTime++; } - Set resultIDs = new HashSet<>(); + ArrayList resultIDs = new ArrayList<>(); DBLock.lock(); - final String query = "SELECT events.event_id AS event_id FROM events" + useHashHitTablesHelper(filter) + useTagTablesHelper(filter) + " WHERE time >= " + startTime + " AND time <" + endTime + " AND " + SQLHelper.getSQLWhere(filter); // NON-NLS + final String query = "SELECT events.event_id AS event_id FROM events" + useHashHitTablesHelper(filter) + useTagTablesHelper(filter) + + " WHERE time >= " + startTime + " AND time <" + endTime + " AND " + SQLHelper.getSQLWhere(filter) + " ORDER BY time ASC"; // NON-NLS try (Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(query)) { while (rs.next()) { @@ -1168,7 +1169,6 @@ public class EventDB { return useSubTypes ? "sub_type" : "base_type"; //NON-NLS } - private PreparedStatement prepareStatement(String queryString) throws SQLException { PreparedStatement prepareStatement = con.prepareStatement(queryString); preparedStatements.add(prepareStatement); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/db/EventsRepository.java b/Core/src/org/sleuthkit/autopsy/timeline/db/EventsRepository.java index a93bf9dc18..9686abb142 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/db/EventsRepository.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/db/EventsRepository.java @@ -214,7 +214,7 @@ public class EventsRepository { idToEventCache.invalidateAll(); } - public Set getEventIDs(Interval timeRange, RootFilter filter) { + public List getEventIDs(Interval timeRange, RootFilter filter) { return eventDB.getEventIDs(timeRange, filter); } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java index 7cb033f9a8..f31b5e4f0d 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java @@ -29,15 +29,12 @@ import java.util.function.Supplier; import javafx.application.Platform; import javafx.beans.InvalidationListener; import javafx.beans.Observable; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; import javafx.fxml.FXML; import javafx.geometry.Insets; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.MenuButton; import javafx.scene.control.TitledPane; -import javafx.scene.control.Toggle; import javafx.scene.control.ToggleButton; import javafx.scene.control.ToolBar; import javafx.scene.control.Tooltip; @@ -60,8 +57,10 @@ import javax.annotation.Nonnull; import javax.annotation.concurrent.GuardedBy; import jfxtras.scene.control.LocalDateTimePicker; import jfxtras.scene.control.LocalDateTimeTextField; +import jfxtras.scene.control.ToggleGroupValue; import org.controlsfx.control.NotificationPane; import org.controlsfx.control.RangeSlider; +import org.controlsfx.control.SegmentedButton; import org.controlsfx.control.action.Action; import org.controlsfx.control.action.ActionUtils; import org.joda.time.DateTime; @@ -162,6 +161,8 @@ final public class VisualizationPanel extends BorderPane { @FXML private Label visualizationModeLabel; @FXML + private SegmentedButton modeSegButton; + @FXML private ToggleButton countsToggle; @FXML private ToggleButton detailsToggle; @@ -261,6 +262,7 @@ final public class VisualizationPanel extends BorderPane { "VisualizationPanel.endLabel.text=End:", "VisualizationPanel.countsToggle.text=Counts", "VisualizationPanel.detailsToggle.text=Details", + "VisualizationPanel.listToggle.text=List", "VisualizationPanel.zoomMenuButton.text=Zoom in/out to", "VisualizationPanel.tagsAddedOrDeleted=Tags have been created and/or deleted. The visualization may not be up to date." }) @@ -280,25 +282,18 @@ final public class VisualizationPanel extends BorderPane { visualizationModeLabel.setText(Bundle.VisualizationPanel_visualizationModeLabel_text()); countsToggle.setText(Bundle.VisualizationPanel_countsToggle_text()); detailsToggle.setText(Bundle.VisualizationPanel_detailsToggle_text()); - ChangeListener toggleListener = (ObservableValue observable, Toggle oldValue, Toggle newValue) -> { - if (newValue == null) { - countsToggle.getToggleGroup().selectToggle(oldValue != null ? oldValue : countsToggle); - } else if (newValue == countsToggle && oldValue != null) { - controller.setVisualizationMode(VisualizationMode.COUNTS); - } else if (newValue == detailsToggle && oldValue != null) { - controller.setVisualizationMode(VisualizationMode.DETAIL); - } else if (newValue == listToggle && oldValue != null) { - controller.setVisualizationMode(VisualizationMode.LIST); - } - }; + listToggle.setText(Bundle.VisualizationPanel_listToggle_text()); - if (countsToggle.getToggleGroup() != null) { - countsToggle.getToggleGroup().selectedToggleProperty().addListener(toggleListener); - } else { - countsToggle.toggleGroupProperty().addListener((Observable toggleGroup) -> { - countsToggle.getToggleGroup().selectedToggleProperty().addListener(toggleListener); - }); - } + ToggleGroupValue visModeToggleGroup = new ToggleGroupValue<>(); + visModeToggleGroup.add(listToggle, VisualizationMode.LIST); + visModeToggleGroup.add(detailsToggle, VisualizationMode.DETAIL); + visModeToggleGroup.add(countsToggle, VisualizationMode.COUNTS); + + modeSegButton.setToggleGroup(visModeToggleGroup); + + visModeToggleGroup.valueProperty().addListener((observable, oldVisMode, newValue) -> { + controller.setVisualizationMode(newValue != null ? newValue : (oldVisMode != null ? oldVisMode : VisualizationMode.COUNTS)); + }); controller.visualizationModeProperty().addListener(visualizationMode -> syncVisualizationMode()); syncVisualizationMode(); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListChart.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListChart.java index b01e9a605a..242c8f6578 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListChart.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListChart.java @@ -7,6 +7,7 @@ package org.sleuthkit.autopsy.timeline.ui.listvew; import java.util.Arrays; import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.value.ObservableValue; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.scene.Node; @@ -14,50 +15,66 @@ import javafx.scene.chart.Axis; import javafx.scene.control.ContextMenu; import javafx.scene.control.TableCell; import javafx.scene.control.TableColumn; +import javafx.scene.control.TableRow; import javafx.scene.control.TableView; -import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.input.MouseEvent; +import javafx.util.Callback; import org.sleuthkit.autopsy.timeline.TimeLineController; -import org.sleuthkit.autopsy.timeline.datamodel.eventtype.EventType; +import org.sleuthkit.autopsy.timeline.datamodel.SingleEvent; import org.sleuthkit.autopsy.timeline.ui.IntervalSelector; import org.sleuthkit.autopsy.timeline.ui.TimeLineChart; -import org.sleuthkit.datamodel.TskData; +import org.sleuthkit.autopsy.timeline.zooming.DescriptionLoD; /** * */ class ListChart extends TableView implements TimeLineChart { + Callback, ObservableValue> cellValueFactory = param -> new SimpleObjectProperty<>(param.getValue()); + private final TimeLineController controller; - private final TableColumn idColumn = new TableColumn<>(); - private final TableColumn millisColumn = new TableColumn<>(); - private final TableColumn iconColumn = new TableColumn<>(); - private final TableColumn descriptionColumn = new TableColumn<>(); - private final TableColumn baseTypeColumn = new TableColumn<>(); - private final TableColumn subTypeColumn = new TableColumn<>(); - private final TableColumn knownColumn = new TableColumn<>(); + private final TableColumn idColumn = new TableColumn<>("Event ID"); + private final TableColumn millisColumn = new TableColumn<>("Date/Time"); + private final TableColumn iconColumn = new TableColumn<>("Icon"); + private final TableColumn descriptionColumn = new TableColumn<>("Description"); + private final TableColumn baseTypeColumn = new TableColumn<>("Base Type"); + private final TableColumn subTypeColumn = new TableColumn<>("Sub Type"); + private final TableColumn knownColumn = new TableColumn<>("Known"); ListChart(TimeLineController controller) { this.controller = controller; - getColumns().addAll(Arrays.asList(idColumn, iconColumn, millisColumn)); + setColumnResizePolicy(CONSTRAINED_RESIZE_POLICY); + getColumns().addAll(Arrays.asList(idColumn, millisColumn, iconColumn, descriptionColumn, baseTypeColumn, subTypeColumn, knownColumn)); - idColumn.setCellValueFactory(param -> new SimpleObjectProperty<>(param.getValue())); + setRowFactory(tableView -> new EventRow()); - millisColumn.setCellValueFactory(param -> { - return new SimpleObjectProperty<>(controller.getEventsModel().getEventById(param.getValue()).getStartMillis()); - }); + idColumn.setCellValueFactory(cellValueFactory); + idColumn.setSortable(false); + + millisColumn.setCellValueFactory(cellValueFactory); millisColumn.setCellFactory(col -> new EpochMillisCell()); - iconColumn.setCellValueFactory(param -> { - return new SimpleObjectProperty<>(controller.getEventsModel().getEventById(param.getValue()).getEventType().getFXImage()); - }); + millisColumn.setSortable(false); + + iconColumn.setCellValueFactory(cellValueFactory); iconColumn.setCellFactory(col -> new ImageCell()); + iconColumn.setSortable(false); - millisColumn.setSortType(TableColumn.SortType.DESCENDING); - millisColumn.setSortable(true); - millisColumn.setComparator(Long::compare); - getSortOrder().setAll(Arrays.asList(millisColumn)); + descriptionColumn.setCellValueFactory(cellValueFactory); + descriptionColumn.setCellFactory(col -> new DescriptionCell()); + descriptionColumn.setSortable(false); + baseTypeColumn.setCellValueFactory(cellValueFactory); + baseTypeColumn.setCellFactory(col -> new BaseTypeCell()); + baseTypeColumn.setSortable(false); + + subTypeColumn.setCellValueFactory(cellValueFactory); + subTypeColumn.setCellFactory(col -> new EventTypeCell()); + subTypeColumn.setSortable(false); + + knownColumn.setCellValueFactory(cellValueFactory); + knownColumn.setCellFactory(col -> new KnownCell()); + knownColumn.setSortable(false); } @Override @@ -105,15 +122,86 @@ class ListChart extends TableView implements TimeLineChart { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } - private static class ImageCell extends TableCell { + private static class ImageCell extends TableCell { @Override - protected void updateItem(Image item, boolean empty) { + protected void updateItem(Long item, boolean empty) { super.updateItem(item, empty); if (empty || item == null) { setGraphic(null); } else { - setGraphic(new ImageView(item)); + EventRow tableRow = (EventRow) getTableRow(); + if (tableRow != null) { + setGraphic(new ImageView(tableRow.getEvent().getEventType().getFXImage())); + } + } + } + } + + private static class DescriptionCell extends TableCell { + + @Override + protected void updateItem(Long item, boolean empty) { + super.updateItem(item, empty); + + if (empty || item == null) { + setText(""); + } else { + EventRow tableRow = (EventRow) getTableRow(); + if (tableRow != null) { + setText(tableRow.getEvent().getDescription(DescriptionLoD.FULL)); + } + } + } + } + + private static class BaseTypeCell extends TableCell { + + @Override + protected void updateItem(Long item, boolean empty) { + super.updateItem(item, empty); + + if (empty || item == null) { + setText(""); + } else { + EventRow tableRow = (EventRow) getTableRow(); + if (tableRow != null) { + setText(tableRow.getEvent().getEventType().getBaseType().getDisplayName()); + } + } + } + } + + private static class EventTypeCell extends TableCell { + + @Override + protected void updateItem(Long item, boolean empty) { + super.updateItem(item, empty); + + if (empty || item == null) { + setText(""); + } else { + EventRow tableRow = (EventRow) getTableRow(); + if (tableRow != null) { + setText(tableRow.getEvent().getEventType().getDisplayName()); + } + } + } + } + + private static class KnownCell extends TableCell { + + @Override + protected void updateItem(Long item, boolean empty) { + super.updateItem(item, empty); + + if (empty || item == null) { + setText(""); + } else { + EventRow tableRow = (EventRow) getTableRow(); + if (tableRow != null) { + setText(tableRow.getEvent().getKnown().getName()); + } } } } @@ -127,9 +215,32 @@ class ListChart extends TableView implements TimeLineChart { if (empty || item == null) { setText(""); } else { - setText(TimeLineController.getZonedFormatter().print(item)); + + EventRow tableRow = (EventRow) getTableRow(); + if (tableRow != null) { + setText(TimeLineController.getZonedFormatter().print(tableRow.getEvent().getStartMillis())); + } } } } + private class EventRow extends TableRow { + + private SingleEvent event; + + SingleEvent getEvent() { + return event; + } + + @Override + protected void updateItem(Long item, boolean empty) { + super.updateItem(item, empty); + + if (empty || item == null) { + event = null; + } else { + event = controller.getEventsModel().getEventById(item); + } + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewPane.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewPane.java index 68b08506df..1bc0c5b088 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewPane.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewPane.java @@ -5,7 +5,7 @@ */ package org.sleuthkit.autopsy.timeline.ui.listvew; -import java.util.Set; +import java.util.List; import javafx.concurrent.Task; import javafx.scene.Node; import javafx.scene.Parent; @@ -116,7 +116,7 @@ public class ListViewPane extends AbstractVisualizationPane eventIDs = eventsModel.getEventIDs(); + List eventIDs = eventsModel.getEventIDs(); getChart().getItems().setAll(eventIDs); // updateMessage(Bundle.DetailViewPane_loggedTask_updateUI()); From 0ffa31d309a8523d7538098f3bfeb530168974c7 Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 16 May 2016 17:49:17 -0400 Subject: [PATCH 014/172] fxmlize the ListView --- .../autopsy/timeline/db/EventDB.java | 2 +- .../ui/AbstractVisualizationPane.java | 2 +- .../autopsy/timeline/ui/TimeLineView.java | 14 +++ .../timeline/ui/listvew/ListChart.java | 115 +++++++++++------- .../timeline/ui/listvew/ListViewChart.fxml | 39 ++++++ .../timeline/ui/listvew/ListViewPane.java | 12 +- 6 files changed, 134 insertions(+), 50 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/timeline/ui/TimeLineView.java create mode 100644 Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewChart.fxml diff --git a/Core/src/org/sleuthkit/autopsy/timeline/db/EventDB.java b/Core/src/org/sleuthkit/autopsy/timeline/db/EventDB.java index 2374e7a032..559b039b41 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/db/EventDB.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/db/EventDB.java @@ -584,7 +584,7 @@ public class EventDB { insertHashHitStmt = prepareStatement("INSERT OR IGNORE INTO hash_set_hits (hash_set_id, event_id) values (?,?)"); //NON-NLS insertTagStmt = prepareStatement("INSERT OR IGNORE INTO tags (tag_id, tag_name_id,tag_name_display_name, event_id) values (?,?,?,?)"); //NON-NLS deleteTagStmt = prepareStatement("DELETE FROM tags WHERE tag_id = ?"); //NON-NLS - countAllEventsStmt = prepareStatement("SELECT count(*) AS count FROM events"); //NON-NLS + countAllEventsStmt = prepareStatement("SELECT count(event_id) AS count FROM events WHERE event_id IS NOT null"); //NON-NLS dropEventsTableStmt = prepareStatement("DROP TABLE IF EXISTS events"); //NON-NLS dropHashSetHitsTableStmt = prepareStatement("DROP TABLE IF EXISTS hash_set_hits"); //NON-NLS dropHashSetsTableStmt = prepareStatement("DROP TABLE IF EXISTS hash_sets"); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualizationPane.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualizationPane.java index fb645bdcd3..ac58f65ca5 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualizationPane.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualizationPane.java @@ -85,7 +85,7 @@ import org.sleuthkit.autopsy.timeline.events.RefreshRequestedEvent; * * TODO: pull up common history context menu items out of derived classes? -jm */ -public abstract class AbstractVisualizationPane> extends BorderPane { +public abstract class AbstractVisualizationPane> extends BorderPane implements TimeLineView { private static final Logger LOGGER = Logger.getLogger(AbstractVisualizationPane.class.getName()); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/TimeLineView.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/TimeLineView.java new file mode 100644 index 0000000000..cfbd3c9f5a --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/TimeLineView.java @@ -0,0 +1,14 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.timeline.ui; + +/** + * + * @author jmillman + */ +public interface TimeLineView { + +} diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListChart.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListChart.java index 242c8f6578..9235b763da 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListChart.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListChart.java @@ -5,21 +5,27 @@ */ package org.sleuthkit.autopsy.timeline.ui.listvew; -import java.util.Arrays; +import java.util.List; +import javafx.beans.binding.Bindings; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.value.ObservableValue; import javafx.collections.FXCollections; import javafx.collections.ObservableList; +import javafx.fxml.FXML; import javafx.scene.Node; import javafx.scene.chart.Axis; import javafx.scene.control.ContextMenu; +import javafx.scene.control.Label; import javafx.scene.control.TableCell; import javafx.scene.control.TableColumn; import javafx.scene.control.TableRow; import javafx.scene.control.TableView; import javafx.scene.image.ImageView; import javafx.scene.input.MouseEvent; +import javafx.scene.layout.BorderPane; import javafx.util.Callback; +import org.sleuthkit.autopsy.coreutils.ThreadConfined; +import org.sleuthkit.autopsy.timeline.FXMLConstructor; import org.sleuthkit.autopsy.timeline.TimeLineController; import org.sleuthkit.autopsy.timeline.datamodel.SingleEvent; import org.sleuthkit.autopsy.timeline.ui.IntervalSelector; @@ -29,7 +35,13 @@ import org.sleuthkit.autopsy.timeline.zooming.DescriptionLoD; /** * */ -class ListChart extends TableView implements TimeLineChart { +class ListChart extends BorderPane implements TimeLineChart { + + @FXML + private Label eventCountLabel; + + @FXML + private TableView table; Callback, ObservableValue> cellValueFactory = param -> new SimpleObjectProperty<>(param.getValue()); @@ -44,37 +56,42 @@ class ListChart extends TableView implements TimeLineChart { ListChart(TimeLineController controller) { this.controller = controller; - setColumnResizePolicy(CONSTRAINED_RESIZE_POLICY); - getColumns().addAll(Arrays.asList(idColumn, millisColumn, iconColumn, descriptionColumn, baseTypeColumn, subTypeColumn, knownColumn)); + FXMLConstructor.construct(this, ListChart.class, "ListViewChart.fxml"); + } - setRowFactory(tableView -> new EventRow()); + @FXML + void initialize() { + assert eventCountLabel != null : "fx:id=\"eventCountLabel\" was not injected: check your FXML file 'ListViewPane.fxml'."; + assert table != null : "fx:id=\"table\" was not injected: check your FXML file 'ListViewPane.fxml'."; + assert idColumn != null : "fx:id=\"idColumn\" was not injected: check your FXML file 'ListViewPane.fxml'."; + assert millisColumn != null : "fx:id=\"millisColumn\" was not injected: check your FXML file 'ListViewPane.fxml'."; + assert iconColumn != null : "fx:id=\"iconColumn\" was not injected: check your FXML file 'ListViewPane.fxml'."; + assert descriptionColumn != null : "fx:id=\"descriptionColumn\" was not injected: check your FXML file 'ListViewPane.fxml'."; + assert baseTypeColumn != null : "fx:id=\"baseTypeColumn\" was not injected: check your FXML file 'ListViewPane.fxml'."; + assert subTypeColumn != null : "fx:id=\"subTypeColumn\" was not injected: check your FXML file 'ListViewPane.fxml'."; + assert knownColumn != null : "fx:id=\"knownColumn\" was not injected: check your FXML file 'ListViewPane.fxml'."; +// setRowFactory(tableView -> new EventRow()); idColumn.setCellValueFactory(cellValueFactory); - idColumn.setSortable(false); millisColumn.setCellValueFactory(cellValueFactory); millisColumn.setCellFactory(col -> new EpochMillisCell()); - millisColumn.setSortable(false); iconColumn.setCellValueFactory(cellValueFactory); iconColumn.setCellFactory(col -> new ImageCell()); - iconColumn.setSortable(false); descriptionColumn.setCellValueFactory(cellValueFactory); descriptionColumn.setCellFactory(col -> new DescriptionCell()); - descriptionColumn.setSortable(false); baseTypeColumn.setCellValueFactory(cellValueFactory); baseTypeColumn.setCellFactory(col -> new BaseTypeCell()); - baseTypeColumn.setSortable(false); subTypeColumn.setCellValueFactory(cellValueFactory); subTypeColumn.setCellFactory(col -> new EventTypeCell()); - subTypeColumn.setSortable(false); knownColumn.setCellValueFactory(cellValueFactory); knownColumn.setCellFactory(col -> new KnownCell()); - knownColumn.setSortable(false); + eventCountLabel.textProperty().bind(Bindings.size(table.getItems()).asString().concat(" events")); } @Override @@ -120,9 +137,20 @@ class ListChart extends TableView implements TimeLineChart { @Override public ContextMenu getContextMenu(MouseEvent m) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } - private static class ImageCell extends TableCell { + @ThreadConfined(type = ThreadConfined.ThreadType.JFX) + void clear() { + table.getItems().clear(); + } + + @ThreadConfined(type = ThreadConfined.ThreadType.JFX) + void setEventIDs(List eventIDs) { + table.getItems().setAll(eventIDs); + } + + private class ImageCell extends EventTableCell { @Override protected void updateItem(Long item, boolean empty) { @@ -130,15 +158,12 @@ class ListChart extends TableView implements TimeLineChart { if (empty || item == null) { setGraphic(null); } else { - EventRow tableRow = (EventRow) getTableRow(); - if (tableRow != null) { - setGraphic(new ImageView(tableRow.getEvent().getEventType().getFXImage())); - } + setGraphic(new ImageView(getEvent().getEventType().getFXImage())); } } } - private static class DescriptionCell extends TableCell { + private class DescriptionCell extends EventTableCell { @Override protected void updateItem(Long item, boolean empty) { @@ -147,15 +172,12 @@ class ListChart extends TableView implements TimeLineChart { if (empty || item == null) { setText(""); } else { - EventRow tableRow = (EventRow) getTableRow(); - if (tableRow != null) { - setText(tableRow.getEvent().getDescription(DescriptionLoD.FULL)); - } + setText(getEvent().getDescription(DescriptionLoD.FULL)); } } } - private static class BaseTypeCell extends TableCell { + private class BaseTypeCell extends EventTableCell { @Override protected void updateItem(Long item, boolean empty) { @@ -164,15 +186,12 @@ class ListChart extends TableView implements TimeLineChart { if (empty || item == null) { setText(""); } else { - EventRow tableRow = (EventRow) getTableRow(); - if (tableRow != null) { - setText(tableRow.getEvent().getEventType().getBaseType().getDisplayName()); - } + setText(getEvent().getEventType().getBaseType().getDisplayName()); } } } - private static class EventTypeCell extends TableCell { + private class EventTypeCell extends EventTableCell { @Override protected void updateItem(Long item, boolean empty) { @@ -181,15 +200,12 @@ class ListChart extends TableView implements TimeLineChart { if (empty || item == null) { setText(""); } else { - EventRow tableRow = (EventRow) getTableRow(); - if (tableRow != null) { - setText(tableRow.getEvent().getEventType().getDisplayName()); - } + setText(getEvent().getEventType().getDisplayName()); } } } - private static class KnownCell extends TableCell { + private class KnownCell extends EventTableCell { @Override protected void updateItem(Long item, boolean empty) { @@ -198,15 +214,32 @@ class ListChart extends TableView implements TimeLineChart { if (empty || item == null) { setText(""); } else { - EventRow tableRow = (EventRow) getTableRow(); - if (tableRow != null) { - setText(tableRow.getEvent().getKnown().getName()); - } + setText(getEvent().getKnown().getName()); } } } - private class EpochMillisCell extends TableCell { + private class EventTableCell extends TableCell { + + private SingleEvent event; + + SingleEvent getEvent() { + return event; + } + + @Override + protected void updateItem(Long item, boolean empty) { + super.updateItem(item, empty); + + if (empty || item == null) { + event = null; + } else { + event = controller.getEventsModel().getEventById(item); + } + } + } + + private class EpochMillisCell extends EventTableCell { @Override protected void updateItem(Long item, boolean empty) { @@ -215,11 +248,7 @@ class ListChart extends TableView implements TimeLineChart { if (empty || item == null) { setText(""); } else { - - EventRow tableRow = (EventRow) getTableRow(); - if (tableRow != null) { - setText(TimeLineController.getZonedFormatter().print(tableRow.getEvent().getStartMillis())); - } + setText(TimeLineController.getZonedFormatter().print(getEvent().getStartMillis())); } } } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewChart.fxml b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewChart.fxml new file mode 100644 index 0000000000..f3b45572c2 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewChart.fxml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+
diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewPane.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewPane.java index 1bc0c5b088..aa6468298d 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewPane.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewPane.java @@ -6,6 +6,7 @@ package org.sleuthkit.autopsy.timeline.ui.listvew; import java.util.List; +import javafx.application.Platform; import javafx.concurrent.Task; import javafx.scene.Node; import javafx.scene.Parent; @@ -15,6 +16,7 @@ import org.sleuthkit.autopsy.timeline.TimeLineController; import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel; import org.sleuthkit.autopsy.timeline.datamodel.SingleEvent; import org.sleuthkit.autopsy.timeline.ui.AbstractVisualizationPane; +import org.sleuthkit.autopsy.timeline.ui.TimeLineView; /** * @param The type of data plotted along the x axis @@ -31,7 +33,7 @@ import org.sleuthkit.autopsy.timeline.ui.AbstractVisualizationPane; * public abstract class AbstractVisualizationPane> extends BorderPane { */ -public class ListViewPane extends AbstractVisualizationPane { +public class ListViewPane extends AbstractVisualizationPane implements TimeLineView { /** * Constructor @@ -88,7 +90,7 @@ public class ListViewPane extends AbstractVisualizationPane eventIDs = eventsModel.getEventIDs(); - getChart().getItems().setAll(eventIDs); + Platform.runLater(() -> getChart().setEventIDs(eventIDs)); -// updateMessage(Bundle.DetailViewPane_loggedTask_updateUI()); + updateMessage("updating ui"); return eventIDs.isEmpty() == false; } From 8155af6ccecce6869bde65c6ef35c519259cc6ed Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Tue, 17 May 2016 10:24:13 -0400 Subject: [PATCH 015/172] Fixed stix source module name. --- .../org/sleuthkit/autopsy/modules/stix/STIXReportModule.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java b/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java index e971eadf25..55fa0a565b 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java @@ -50,6 +50,7 @@ import org.mitre.stix.common_1.IndicatorBaseType; import org.mitre.stix.indicator_2.Indicator; import org.mitre.stix.stix_1.STIXPackage; import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; @@ -96,6 +97,7 @@ public class STIXReportModule implements GeneralReportModule { * @param progressPanel panel to update the report's progress */ @Override + @Messages({"STIXReportModule.srcModuleName.text=STIX Report"}) public void generateReport(String baseReportDir, ReportProgressPanel progressPanel) { // Start the progress bar and setup the report progressPanel.setIndeterminate(false); @@ -191,7 +193,7 @@ public class STIXReportModule implements GeneralReportModule { // Set the progress bar to done. If any errors occurred along the way, modify // the "complete" message to indicate this. - Case.getCurrentCase().addReport(reportPath, stixFileName, ""); + Case.getCurrentCase().addReport(reportPath, Bundle.STIXReportModule_srcModuleName_text(), ""); if (hadErrors) { progressPanel.complete(ReportStatus.ERROR); progressPanel.updateStatusLabel( From 0d775fd85fa0012272bc140046b625e101aad380 Mon Sep 17 00:00:00 2001 From: Karl Mortensen Date: Tue, 17 May 2016 10:25:44 -0400 Subject: [PATCH 016/172] Move Open Output Folder to Tools menu --- .../org/sleuthkit/autopsy/actions/OpenOutputFolderAction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/actions/OpenOutputFolderAction.java b/Core/src/org/sleuthkit/autopsy/actions/OpenOutputFolderAction.java index 2ea5c95538..8ae0849c7f 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/OpenOutputFolderAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/OpenOutputFolderAction.java @@ -39,7 +39,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; */ @ActionRegistration( displayName = "#CTL_OpenOutputFolder", iconInMenu = true) -@ActionReference(path = "Menu/Help", position = 1850) +@ActionReference(path = "Menu/Tools", position = 1850, separatorBefore = 1849) @ActionID(id = "org.sleuthkit.autopsy.actions.OpenOutputFolderAction", category = "Help") public final class OpenOutputFolderAction implements ActionListener { From 2754c5039592657d0f8122426a6fbc6c401b2c5d Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Tue, 17 May 2016 11:33:46 -0400 Subject: [PATCH 017/172] Started adding cancellation. --- .../autopsy/keywordsearch/KeywordSearchIngestModule.java | 3 +-- .../sleuthkit/autopsy/keywordsearch/StringsTextExtractor.java | 3 ++- .../src/org/sleuthkit/autopsy/keywordsearch/TextExtractor.java | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java index cda05d86b3..10f43b4534 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java @@ -29,7 +29,6 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; -import org.sleuthkit.autopsy.coreutils.StringExtract.StringExtractUnicodeTable.SCRIPT; import org.sleuthkit.autopsy.ingest.FileIngestModule; import org.sleuthkit.autopsy.ingest.IngestJobContext; import org.sleuthkit.autopsy.ingest.IngestMessage; @@ -431,7 +430,7 @@ public final class KeywordSearchIngestModule implements FileIngestModule { */ private boolean extractStringsAndIndex(AbstractFile aFile) { try { - if (stringExtractor.index(aFile)) { + if (stringExtractor.index(aFile, KeywordSearchIngestModule.this.context)) { putIngestStatus(jobId, aFile.getId(), IngestStatus.STRINGS_INGESTED); return true; } else { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/StringsTextExtractor.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/StringsTextExtractor.java index 7599ce1c85..9b0fd107d0 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/StringsTextExtractor.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/StringsTextExtractor.java @@ -28,6 +28,7 @@ import java.util.Map; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.StringExtract.StringExtractUnicodeTable.SCRIPT; +import org.sleuthkit.autopsy.ingest.IngestJobContext; import org.sleuthkit.autopsy.keywordsearch.Ingester.IngesterException; import org.sleuthkit.datamodel.AbstractFile; @@ -96,7 +97,7 @@ class StringsTextExtractor implements TextExtractor { } @Override - public boolean index(AbstractFile sourceFile) throws IngesterException { + public boolean index(AbstractFile sourceFile, IngestJobContext context) throws IngesterException { this.sourceFile = sourceFile; this.numChunks = 0; //unknown until indexing is done boolean success = false; diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TextExtractor.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TextExtractor.java index 92892238df..949430bf72 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TextExtractor.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TextExtractor.java @@ -22,6 +22,7 @@ import java.util.Arrays; import java.util.List; import java.util.Map; import org.sleuthkit.autopsy.coreutils.StringExtract.StringExtractUnicodeTable.SCRIPT; +import org.sleuthkit.autopsy.ingest.IngestJobContext; import org.sleuthkit.datamodel.AbstractFile; /** @@ -99,7 +100,7 @@ interface TextExtractor { * * @throws org.sleuthkit.autopsy.keywordsearch.Ingester.IngesterException */ - boolean index(AbstractFile sourceFile) throws Ingester.IngesterException; + boolean index(AbstractFile sourceFile, IngestJobContext context) throws Ingester.IngesterException; /** * Sets the scripts to use for the extraction From 4d14c32a94e3fce033f8b52b0423047191fd0659 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 17 May 2016 12:15:41 -0400 Subject: [PATCH 018/172] split AbstractVisualizationPane into AbstractTimeLineView and AbstractTimelineChart CountsViewPane and DetailViewPane extend AbstractTimelineChart, ListViewPane extends AbstractTimeLineView --- .../timeline/ui/AbstractTimeLineView.java | 360 +++++++++++++++++ ...onPane.java => AbstractTimelineChart.java} | 377 +----------------- .../autopsy/timeline/ui/TimeLineView.java | 14 - .../timeline/ui/VisualizationPanel.java | 4 +- .../ui/countsview/CountsViewPane.java | 12 +- .../ui/detailview/DetailViewPane.java | 13 +- .../timeline/ui/detailview/DetailsChart.java | 5 + .../ui/detailview/DetailsChartLane.java | 4 +- .../timeline/ui/detailview/EventNodeBase.java | 6 +- .../timeline/ui/detailview/GuideLine.java | 4 +- .../timeline/ui/listvew/ListChart.java | 51 ++- .../timeline/ui/listvew/ListViewChart.fxml | 12 +- .../timeline/ui/listvew/ListViewPane.java | 63 +-- 13 files changed, 452 insertions(+), 473 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractTimeLineView.java rename Core/src/org/sleuthkit/autopsy/timeline/ui/{AbstractVisualizationPane.java => AbstractTimelineChart.java} (57%) delete mode 100644 Core/src/org/sleuthkit/autopsy/timeline/ui/TimeLineView.java diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractTimeLineView.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractTimeLineView.java new file mode 100644 index 0000000000..e890a7387a --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractTimeLineView.java @@ -0,0 +1,360 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.timeline.ui; + +import com.google.common.eventbus.Subscribe; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.logging.Level; +import javafx.application.Platform; +import javafx.beans.InvalidationListener; +import javafx.beans.Observable; +import javafx.beans.property.ReadOnlyBooleanProperty; +import javafx.beans.property.ReadOnlyBooleanWrapper; +import javafx.concurrent.Task; +import javafx.scene.Cursor; +import javafx.scene.Node; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.StackPane; +import org.controlsfx.control.MaskerPane; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.coreutils.LoggedTask; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.ThreadConfined; +import org.sleuthkit.autopsy.timeline.TimeLineController; +import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel; +import org.sleuthkit.autopsy.timeline.events.RefreshRequestedEvent; + +public abstract class AbstractTimeLineView extends BorderPane { + + private static final Logger LOGGER = Logger.getLogger(AbstractTimeLineView.class.getName()); + + /** + * Boolean property that holds true if the visualization does not show any + * events with the current zoom and filter settings. + */ + private final ReadOnlyBooleanWrapper hasVisibleEvents = new ReadOnlyBooleanWrapper(true); + + /** + * Boolean property that holds true if the visualization may not represent + * the current state of the DB, because, for example, tags have been updated + * but the vis. was not refreshed. + */ + private final ReadOnlyBooleanWrapper outOfDate = new ReadOnlyBooleanWrapper(false); + + /** + * List of Nodes to insert into the toolbar. This should be set in an + * implementations constructor. + */ + private List settingsNodes; + + /** + * Listener that is attached to various properties that should trigger a vis + * update when they change. + */ + private InvalidationListener updateListener = (Observable any) -> refresh(); + + /** + * task used to reload the content of this visualization + */ + private Task updateTask; + + private final TimeLineController controller; + private final FilteredEventsModel filteredEvents; + + /** + * Constructor + * + * @param controller + */ + public AbstractTimeLineView(TimeLineController controller) { + this.controller = controller; + this.filteredEvents = controller.getEventsModel(); + this.filteredEvents.registerForEvents(this); + this.filteredEvents.zoomParametersProperty().addListener(updateListener); + TimeLineController.getTimeZone().addListener(updateListener); + } + + /** + * Handle a RefreshRequestedEvent from the events model by updating the + * visualization. + * + * @param event The RefreshRequestedEvent to handle. + */ + @Subscribe + public void handleRefreshRequested(RefreshRequestedEvent event) { + refresh(); + } + + /** + * Does the visualization represent an out-of-date state of the DB. It might + * if, for example, tags have been updated but the vis. was not refreshed. + * + * @return True if the visualization does not represent the curent state of + * the DB. + */ + public boolean isOutOfDate() { + return outOfDate.get(); + } + + /** + * Get a ReadOnlyBooleanProperty that holds true if this visualization does + * not represent the current state of the DB> + * + * @return A ReadOnlyBooleanProperty that holds the out-of-date state for + * this visualization. + */ + public ReadOnlyBooleanProperty outOfDateProperty() { + return outOfDate.getReadOnlyProperty(); + } + + /** + * Get the TimelineController for this visualization. + * + * @return The TimelineController for this visualization. + */ + protected TimeLineController getController() { + return controller; + } + + /** + * Refresh this visualization based on current state of zoom / filters. + * Primarily this invokes the background VisualizationUpdateTask returned by + * getUpdateTask(), which derived classes must implement. + * + * TODO: replace this logic with a javafx Service ? -jm + */ + protected final synchronized void refresh() { + if (updateTask != null) { + updateTask.cancel(true); + updateTask = null; + } + updateTask = getNewUpdateTask(); + updateTask.stateProperty().addListener((Observable observable) -> { + switch (updateTask.getState()) { + case CANCELLED: + case FAILED: + case READY: + case RUNNING: + case SCHEDULED: + break; + case SUCCEEDED: + try { + this.hasVisibleEvents.set(updateTask.get()); + } catch (InterruptedException | ExecutionException ex) { + LOGGER.log(Level.SEVERE, "Unexpected exception updating visualization", ex); //NON-NLS + } + break; + } + }); + getController().monitorTask(updateTask); + } + + /** + * Get the FilteredEventsModel for this visualization. + * + * @return The FilteredEventsModel for this visualization. + */ + protected FilteredEventsModel getEventsModel() { + return filteredEvents; + } + + /** + * Get a new background Task that fetches the appropriate data and loads it + * into this visualization. + * + * @return A new task to execute on a background thread to reload this + * visualization with different data. + */ + protected abstract Task getNewUpdateTask(); + + /** + * Get a List of nodes containing settings widgets to insert into this + * visualization's header. + * + * @return The List of settings Nodes. + */ + protected List getSettingsNodes() { + return Collections.unmodifiableList(settingsNodes); + } + + /** + * Set the List of nodes containing settings widgets to insert into this + * visualization's header. + * + * + * @param settingsNodes The List of nodes containing settings widgets to + * insert into this visualization's header. + */ + final protected void setSettingsNodes(List settingsNodes) { + this.settingsNodes = new ArrayList<>(settingsNodes); + } + + /** + * Dispose of this visualization and any resources it holds onto. + */ + final synchronized void dispose() { + //cancel and gc updateTask + if (updateTask != null) { + updateTask.cancel(true); + updateTask = null; + } + //remvoe and gc updateListener + this.filteredEvents.zoomParametersProperty().removeListener(updateListener); + TimeLineController.getTimeZone().removeListener(updateListener); + updateListener = null; + filteredEvents.unRegisterForEvents(this); + } + + /** + * Are there are any events visible in this visualization with the current + * view parameters? + * + * @return True if there are events visible in this visualization with the + * current view parameters. + */ + boolean hasVisibleEvents() { + return hasVisibleEventsProperty().get(); + } + + /** + * A property that indicates whether there are any events visible in this + * visualization with the current view parameters. + * + * @return A property that indicates whether there are any events visible in + * this visualization with the current view parameters. + */ + ReadOnlyBooleanProperty hasVisibleEventsProperty() { + return hasVisibleEvents.getReadOnlyProperty(); + } + + /** + * Set this visualization out of date because, for example, tags have been + * updated but the vis. was not refreshed. + */ + void setOutOfDate() { + outOfDate.set(true); + } + + /** + * Clear all data items from this chart. + */ + @ThreadConfined(type = ThreadConfined.ThreadType.JFX) + abstract protected void clearData(); + + /** + * Base class for Tasks that refreshes a view when the view settings change. + * + * @param The type of a single object that can represent + * the range of data displayed along the X-Axis. + */ + protected abstract class ViewRefreshTask extends LoggedTask { + + private final Node center; + + /** + * Constructor + * + * @param taskName The name of this task. + * @param logStateChanges Whether or not task state changes should be + * logged. + */ + protected ViewRefreshTask(String taskName, boolean logStateChanges) { + super(taskName, logStateChanges); + this.center = getCenter(); + } + + /** + * Sets initial progress value and message and shows blocking progress + * indicator over the visualization. Derived Tasks should be sure to + * call this as part of their call() implementation. + * + * @return True + * + * @throws Exception If there is an unhandled exception during the + * background operation + */ + @NbBundle.Messages(value = {"VisualizationUpdateTask.preparing=Analyzing zoom and filter settings"}) + @Override + protected Boolean call() throws Exception { + updateProgress(-1, 1); + updateMessage(Bundle.VisualizationUpdateTask_preparing()); + Platform.runLater(() -> { + MaskerPane maskerPane = new MaskerPane(); + maskerPane.textProperty().bind(messageProperty()); + maskerPane.progressProperty().bind(progressProperty()); + setCenter(new StackPane(center, maskerPane)); + setCursor(Cursor.WAIT); + }); + return true; + } + + /** + * Updates the horizontal axis and removes the blocking progress + * indicator. Derived Tasks should be sure to call this as part of their + * succeeded() implementation. + */ + @Override + protected void succeeded() { + super.succeeded(); + outOfDate.set(false); + cleanup(); + } + + /** + * Removes the blocking progress indicator. Derived Tasks should be sure + * to call this as part of their cancelled() implementation. + */ + @Override + protected void cancelled() { + super.cancelled(); + cleanup(); + } + + /** + * Removes the blocking progress indicator. Derived Tasks should be sure + * to call this as part of their failed() implementation. + */ + @Override + protected void failed() { + super.failed(); + cleanup(); + } + + /** + * Removes the blocking progress indicator and reset the cursor to the + * default. + */ + private void cleanup() { + setCenter(center); //clear masker pane installed in call() + setCursor(Cursor.DEFAULT); + } + + /** + * Set the horizontal range that this chart will show. + * + * @param values A single object representing the range that this chart + * will show. + */ + protected abstract void setDateValues(AxisValuesType values); + + /** + * Clears the chart data and sets the horizontal axis range. For use + * within the derived implementation of the call() method. + * + * @param axisValues + */ + @ThreadConfined(type = ThreadConfined.ThreadType.NOT_UI) + protected void resetView(AxisValuesType axisValues) { + Platform.runLater(() -> { + clearData(); + setDateValues(axisValues); + }); + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualizationPane.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractTimelineChart.java similarity index 57% rename from Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualizationPane.java rename to Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractTimelineChart.java index ac58f65ca5..17209b9a4b 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualizationPane.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractTimelineChart.java @@ -18,27 +18,14 @@ */ package org.sleuthkit.autopsy.timeline.ui; -import com.google.common.eventbus.Subscribe; -import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; import java.util.HashMap; -import java.util.List; import java.util.Map; -import java.util.concurrent.ExecutionException; -import java.util.logging.Level; -import javafx.application.Platform; -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; -import javafx.beans.property.ReadOnlyBooleanProperty; -import javafx.beans.property.ReadOnlyBooleanWrapper; import javafx.collections.FXCollections; import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; import javafx.collections.transformation.SortedList; -import javafx.concurrent.Task; import javafx.geometry.Pos; -import javafx.scene.Cursor; import javafx.scene.Node; import javafx.scene.chart.Axis; import javafx.scene.chart.XYChart; @@ -46,14 +33,12 @@ import javafx.scene.control.Label; import javafx.scene.control.OverrunStyle; import javafx.scene.control.Tooltip; import javafx.scene.layout.Border; -import javafx.scene.layout.BorderPane; import javafx.scene.layout.BorderStroke; import javafx.scene.layout.BorderStrokeStyle; import javafx.scene.layout.BorderWidths; import javafx.scene.layout.CornerRadii; import javafx.scene.layout.Pane; import javafx.scene.layout.Region; -import javafx.scene.layout.StackPane; import javafx.scene.paint.Color; import javafx.scene.text.Font; import javafx.scene.text.FontWeight; @@ -61,15 +46,11 @@ import javafx.scene.text.Text; import javafx.scene.text.TextAlignment; import javax.annotation.concurrent.Immutable; import org.apache.commons.lang3.StringUtils; -import org.controlsfx.control.MaskerPane; import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.coreutils.LoggedTask; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.timeline.TimeLineController; -import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel; import org.sleuthkit.autopsy.timeline.datamodel.eventtype.EventType; -import org.sleuthkit.autopsy.timeline.events.RefreshRequestedEvent; /** * Abstract base class for TimeLineChart based visualizations. @@ -85,9 +66,9 @@ import org.sleuthkit.autopsy.timeline.events.RefreshRequestedEvent; * * TODO: pull up common history context menu items out of derived classes? -jm */ -public abstract class AbstractVisualizationPane> extends BorderPane implements TimeLineView { +public abstract class AbstractTimelineChart> extends AbstractTimeLineView { - private static final Logger LOGGER = Logger.getLogger(AbstractVisualizationPane.class.getName()); + private static final Logger LOGGER = Logger.getLogger(AbstractTimelineChart.class.getName()); @NbBundle.Messages("AbstractVisualization.Default_Tooltip.text=Drag the mouse to select a time interval to zoom into.\nRight-click for more actions.") private static final Tooltip DEFAULT_TOOLTIP = new Tooltip(Bundle.AbstractVisualization_Default_Tooltip_text()); @@ -99,22 +80,19 @@ public abstract class AbstractVisualizationPane of the nodes that are selected in + * this visualization. */ - private final ReadOnlyBooleanWrapper outOfDate = new ReadOnlyBooleanWrapper(false); - - /** - * Boolean property that holds true if the visualization does not show any - * events with the current zoom and filter settings. - */ - private final ReadOnlyBooleanWrapper hasVisibleEvents = new ReadOnlyBooleanWrapper(true); + protected ObservableList getSelectedNodes() { + return selectedNodes; + } /** * Access to chart data via series @@ -127,54 +105,11 @@ public abstract class AbstractVisualizationPane updateTask; - - final private TimeLineController controller; - final private FilteredEventsModel filteredEvents; - final private ObservableList selectedNodes = FXCollections.observableArrayList(); - /** - * Listener that is attached to various properties that should trigger a vis - * update when they change. - */ - private InvalidationListener updateListener = any -> refresh(); - - /** - * Does the visualization represent an out-of-date state of the DB. It might - * if, for example, tags have been updated but the vis. was not refreshed. - * - * @return True if the visualization does not represent the curent state of - * the DB. - */ - public boolean isOutOfDate() { - return outOfDate.get(); - } - - /** - * Set this visualization out of date because, for example, tags have been - * updated but the vis. was not refreshed. - */ - void setOutOfDate() { - outOfDate.set(true); - } - - /** - * Get a ReadOnlyBooleanProperty that holds true if this visualization does - * not represent the current state of the DB> - * - * @return A ReadOnlyBooleanProperty that holds the out-of-date state for - * this visualization. - */ - public ReadOnlyBooleanProperty outOfDateProperty() { - return outOfDate.getReadOnlyProperty(); - } - public Pane getSpecificLabelPane() { return specificLabelPane; } @@ -187,53 +122,6 @@ public abstract class AbstractVisualizationPane of the nodes that are selected in - * this visualization. - */ - protected ObservableList getSelectedNodes() { - return selectedNodes; - } - - /** - * List of Nodes to insert into the toolbar. This should be set in an - * implementations constructor. - */ - private List settingsNodes; - - /** - * Get a List of nodes containing settings widgets to insert into this - * visualization's header. - * - * @return The List of settings Nodes. - */ - protected List getSettingsNodes() { - return Collections.unmodifiableList(settingsNodes); - } - - /** - * Set the List of nodes containing settings widgets to insert into this - * visualization's header. - * - * - * @param settingsNodes The List of nodes containing settings widgets to - * insert into this visualization's header. - */ - protected void setSettingsNodes(List settingsNodes) { - this.settingsNodes = new ArrayList<>(settingsNodes); - } - - /** - * Get the TimelineController for this visualization. - * - * @return The TimelineController for this visualization. - */ - protected TimeLineController getController() { - return controller; - } - /** * Get the CharType that implements this visualization. * @@ -243,15 +131,6 @@ public abstract class AbstractVisualizationPane getNewUpdateTask(); - /** * Get the label that should be used for a tick mark at the given value. * @@ -373,74 +221,6 @@ public abstract class AbstractVisualizationPane { - switch (updateTask.getState()) { - case CANCELLED: - case FAILED: - case READY: - case RUNNING: - case SCHEDULED: - break; - case SUCCEEDED: - try { - this.hasVisibleEvents.set(updateTask.get()); - } catch (InterruptedException | ExecutionException ex) { - LOGGER.log(Level.SEVERE, "Unexpected exception updating visualization", ex); //NON-NLS - } - break; - } - }); - controller.monitorTask(updateTask); - } - - /** - * Handle a RefreshRequestedEvent from the events model by updating the - * visualization. - * - * @param event The RefreshRequestedEvent to handle. - */ - @Subscribe - public void handleRefreshRequested(RefreshRequestedEvent event) { - refresh(); - } - - /** - * Dispose of this visualization and any resources it holds onto. - */ - final synchronized void dispose() { - - //cancel and gc updateTask - if (updateTask != null) { - updateTask.cancel(true); - updateTask = null; - } - //remvoe and gc updateListener - this.filteredEvents.zoomParametersProperty().removeListener(updateListener); - TimeLineController.getTimeZone().removeListener(updateListener); - updateListener = null; - - filteredEvents.unRegisterForEvents(this); - } - /** * Make a series for each event type in a consistent order. */ @@ -470,23 +250,8 @@ public abstract class AbstractVisualizationPane { -// VBox vBox = new VBox(specificLabelPane, contextLabelPane); -// vBox.setFillWidth(false); -// HBox hBox = new HBox(spacer, vBox); -// hBox.setFillHeight(false); -// setBottom(hBox); -// DoubleBinding spacerSize = getYAxis().widthProperty().add(getYAxis().tickLengthProperty()).add(getAxisMargin()); -// spacer.minWidthProperty().bind(spacerSize); -// spacer.prefWidthProperty().bind(spacerSize); -// spacer.maxWidthProperty().bind(spacerSize); -// }); - + protected AbstractTimelineChart(TimeLineController controller) { + super(controller); createSeries(); selectedNodes.addListener((ListChangeListener.Change change) -> { @@ -496,10 +261,8 @@ public abstract class AbstractVisualizationPane controller.setStatusMessage(isHover() ? DEFAULT_TOOLTIP.getText() : "")); + hoverProperty().addListener(hoverProp -> controller.setStatusMessage(isHover() ? getDefaultTooltip().getText() : "")); } @@ -690,116 +453,4 @@ public abstract class AbstractVisualizationPane The type of a single object that can represent - * the range of data displayed along the X-Axis. - */ - abstract protected class VisualizationRefreshTask extends LoggedTask { - - private final Node center; - - /** - * Constructor - * - * @param taskName The name of this task. - * @param logStateChanges Whether or not task state changes should be - * logged. - */ - protected VisualizationRefreshTask(String taskName, boolean logStateChanges) { - super(taskName, logStateChanges); - this.center = getCenter(); - } - - /** - * Sets initial progress value and message and shows blocking progress - * indicator over the visualization. Derived Tasks should be sure to - * call this as part of their call() implementation. - * - * @return True - * - * @throws Exception If there is an unhandled exception during the - * background operation - */ - @NbBundle.Messages({"VisualizationUpdateTask.preparing=Analyzing zoom and filter settings"}) - @Override - protected Boolean call() throws Exception { - updateProgress(-1, 1); - updateMessage(Bundle.VisualizationUpdateTask_preparing()); - Platform.runLater(() -> { - MaskerPane maskerPane = new MaskerPane(); - maskerPane.textProperty().bind(messageProperty()); - maskerPane.progressProperty().bind(progressProperty()); - setCenter(new StackPane(center, maskerPane)); - setCursor(Cursor.WAIT); - }); - - return true; - } - - /** - * Updates the horizontal axis and removes the blocking progress - * indicator. Derived Tasks should be sure to call this as part of their - * succeeded() implementation. - */ - @Override - protected void succeeded() { - super.succeeded(); - outOfDate.set(false); - cleanup(); - } - - /** - * Removes the blocking progress indicator. Derived Tasks should be sure - * to call this as part of their cancelled() implementation. - */ - @Override - protected void cancelled() { - super.cancelled(); - cleanup(); - } - - /** - * Removes the blocking progress indicator. Derived Tasks should be sure - * to call this as part of their failed() implementation. - */ - @Override - protected void failed() { - super.failed(); - cleanup(); - } - - /** - * Removes the blocking progress indicator and reset the cursor to the - * default. - */ - private void cleanup() { - setCenter(center); //clear masker pane installed in call() - setCursor(Cursor.DEFAULT); - } - - /** - * Clears the chart data and sets the horizontal axis range. For use - * within the derived implementation of the call() method. - * - * @param axisValues - */ - @ThreadConfined(type = ThreadConfined.ThreadType.NOT_UI) - protected void resetChart(AxisValuesType axisValues) { - Platform.runLater(() -> { - clearChartData(); - setDateAxisValues(axisValues); - }); - } - - /** - * Set the horizontal range that this chart will show. - * - * @param values A single object representing the range that this chart - * will show. - */ - abstract protected void setDateAxisValues(AxisValuesType values); - } } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/TimeLineView.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/TimeLineView.java deleted file mode 100644 index cfbd3c9f5a..0000000000 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/TimeLineView.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.sleuthkit.autopsy.timeline.ui; - -/** - * - * @author jmillman - */ -public interface TimeLineView { - -} diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java index f31b5e4f0d..14e92b2998 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java @@ -121,7 +121,7 @@ final public class VisualizationPanel extends BorderPane { private LoggedTask histogramTask; private final EventsTree eventsTree; - private AbstractVisualizationPane visualization; + private AbstractTimeLineView visualization; /* * HBox that contains the histogram bars. @@ -580,7 +580,7 @@ final public class VisualizationPanel extends BorderPane { * AbstractVislualization for one of the correct type. */ private void syncVisualizationMode() { - AbstractVisualizationPane vizPane; + AbstractTimeLineView vizPane; VisualizationMode visMode = controller.visualizationModeProperty().get(); //make new visualization. diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/CountsViewPane.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/CountsViewPane.java index 575a6ca900..c5d9ddb6a4 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/CountsViewPane.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/CountsViewPane.java @@ -60,7 +60,7 @@ import org.sleuthkit.autopsy.timeline.FXMLConstructor; import org.sleuthkit.autopsy.timeline.TimeLineController; import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel; import org.sleuthkit.autopsy.timeline.datamodel.eventtype.EventType; -import org.sleuthkit.autopsy.timeline.ui.AbstractVisualizationPane; +import org.sleuthkit.autopsy.timeline.ui.AbstractTimelineChart; import org.sleuthkit.autopsy.timeline.utils.RangeDivisionInfo; /** @@ -79,7 +79,7 @@ import org.sleuthkit.autopsy.timeline.utils.RangeDivisionInfo; * Platform.runLater(java.lang.Runnable). The FilteredEventsModel should * encapsulate all need synchronization internally. */ -public class CountsViewPane extends AbstractVisualizationPane { +public class CountsViewPane extends AbstractTimelineChart { private static final Logger LOGGER = Logger.getLogger(CountsViewPane.class.getName()); @@ -170,7 +170,7 @@ public class CountsViewPane extends AbstractVisualizationPane series : dataSeries) { series.getData().clear(); } @@ -349,7 +349,7 @@ public class CountsViewPane extends AbstractVisualizationPane> { + private class CountsUpdateTask extends ViewRefreshTask> { CountsUpdateTask() { super(Bundle.CountsViewPane_loggedTask_name(), true); @@ -374,7 +374,7 @@ public class CountsViewPane extends AbstractVisualizationPane intervals = rangeInfo.getIntervals(); //clear old data, and reset ranges and series - resetChart(Lists.transform(intervals, rangeInfo::formatForTick)); + resetView(Lists.transform(intervals, rangeInfo::formatForTick)); updateMessage(Bundle.CountsViewPane_loggedTask_updatingCounts()); int chartMax = 0; @@ -432,7 +432,7 @@ public class CountsViewPane extends AbstractVisualizationPane categories) { + protected void setDateValues(List categories) { dateAxis.getCategories().setAll(categories); } } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/DetailViewPane.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/DetailViewPane.java index 13d76c6977..c3998e7cda 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/DetailViewPane.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/DetailViewPane.java @@ -56,7 +56,7 @@ import org.sleuthkit.autopsy.timeline.TimeLineController; import org.sleuthkit.autopsy.timeline.datamodel.EventStripe; import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel; import org.sleuthkit.autopsy.timeline.datamodel.TimeLineEvent; -import org.sleuthkit.autopsy.timeline.ui.AbstractVisualizationPane; +import org.sleuthkit.autopsy.timeline.ui.AbstractTimelineChart; import org.sleuthkit.autopsy.timeline.utils.MappedList; import org.sleuthkit.autopsy.timeline.zooming.DescriptionLoD; import org.sleuthkit.autopsy.timeline.zooming.ZoomParams; @@ -75,7 +75,7 @@ import org.sleuthkit.autopsy.timeline.zooming.ZoomParams; * grouped EventStripes, etc, etc. The leaves of the trees are EventClusters or * SingleEvents. */ -public class DetailViewPane extends AbstractVisualizationPane, DetailsChart> { +public class DetailViewPane extends AbstractTimelineChart, DetailsChart> { private final static Logger LOGGER = Logger.getLogger(DetailViewPane.class.getName()); @@ -218,7 +218,7 @@ public class DetailViewPane extends AbstractVisualizationPane { + private class DetailsUpdateTask extends ViewRefreshTask { DetailsUpdateTask() { super(Bundle.DetailViewPane_loggedTask_name(), true); @@ -423,7 +422,7 @@ public class DetailViewPane extends AbstractVisualizationPane { return nestedEvents; } + Tooltip getDefaultTooltip() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + /** * Clear any time based UI elements (GuideLines, IntervalSelector,...) from * this chart. diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/DetailsChartLane.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/DetailsChartLane.java index b1e67e7eca..8dc24adff2 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/DetailsChartLane.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/DetailsChartLane.java @@ -58,7 +58,7 @@ import org.sleuthkit.autopsy.timeline.datamodel.SingleEvent; import org.sleuthkit.autopsy.timeline.datamodel.TimeLineEvent; import org.sleuthkit.autopsy.timeline.filters.AbstractFilter; import org.sleuthkit.autopsy.timeline.filters.DescriptionFilter; -import org.sleuthkit.autopsy.timeline.ui.AbstractVisualizationPane; +import org.sleuthkit.autopsy.timeline.ui.AbstractTimelineChart; import org.sleuthkit.autopsy.timeline.ui.ContextMenuProvider; /** @@ -178,7 +178,7 @@ abstract class DetailsChartLane extends XYChart()))); - Tooltip.install(this, AbstractVisualizationPane.getDefaultTooltip()); + Tooltip.install(this, AbstractTimelineChart.getDefaultTooltip()); dateAxis.setAutoRanging(false); setLegendVisible(false); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/EventNodeBase.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/EventNodeBase.java index 66bdb7fdf3..4af8dd8c06 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/EventNodeBase.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/EventNodeBase.java @@ -77,7 +77,7 @@ import org.sleuthkit.autopsy.timeline.datamodel.TimeLineEvent; import org.sleuthkit.autopsy.timeline.datamodel.eventtype.EventType; import org.sleuthkit.autopsy.timeline.events.TagsAddedEvent; import org.sleuthkit.autopsy.timeline.events.TagsDeletedEvent; -import org.sleuthkit.autopsy.timeline.ui.AbstractVisualizationPane; +import org.sleuthkit.autopsy.timeline.ui.AbstractTimelineChart; import org.sleuthkit.autopsy.timeline.ui.ContextMenuProvider; import static org.sleuthkit.autopsy.timeline.ui.detailview.EventNodeBase.show; import static org.sleuthkit.autopsy.timeline.ui.detailview.MultiEventNodeBase.CORNER_RADII_3; @@ -167,7 +167,7 @@ public abstract class EventNodeBase extends StackPan //set up mouse hover effect and tooltip setOnMouseEntered(mouseEntered -> { - Tooltip.uninstall(chartLane, AbstractVisualizationPane.getDefaultTooltip()); + Tooltip.uninstall(chartLane, AbstractTimelineChart.getDefaultTooltip()); showHoverControls(true); toFront(); }); @@ -176,7 +176,7 @@ public abstract class EventNodeBase extends StackPan if (parentNode != null) { parentNode.showHoverControls(true); } else { - Tooltip.install(chartLane, AbstractVisualizationPane.getDefaultTooltip()); + Tooltip.install(chartLane, AbstractTimelineChart.getDefaultTooltip()); } }); setOnMouseClicked(new ClickHandler()); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/GuideLine.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/GuideLine.java index bbdd039a11..67e4de1c05 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/GuideLine.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/GuideLine.java @@ -25,7 +25,6 @@ import javafx.scene.shape.Line; import org.joda.time.DateTime; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.timeline.TimeLineController; -import org.sleuthkit.autopsy.timeline.ui.AbstractVisualizationPane; /** * Subclass of {@link Line} with appropriate behavior (mouse listeners) to act @@ -35,7 +34,7 @@ import org.sleuthkit.autopsy.timeline.ui.AbstractVisualizationPane; "GuideLine.tooltip.text={0}\nRight-click to remove.\nDrag to reposition."}) class GuideLine extends Line { - private static final Tooltip CHART_DEFAULT_TOOLTIP = AbstractVisualizationPane.getDefaultTooltip(); + private final Tooltip CHART_DEFAULT_TOOLTIP ; private final Tooltip tooltip = new Tooltip(); private final DetailsChart chart; @@ -49,6 +48,7 @@ class GuideLine extends Line { */ GuideLine(DetailsChart chart) { super(0, 0, 0, 0); + CHART_DEFAULT_TOOLTIP = chart.getDefaultTooltip(); this.chart = chart; Axis xAxis = chart.getXAxis(); endYProperty().bind(chart.heightProperty().subtract(xAxis.heightProperty().subtract(xAxis.tickLengthProperty()))); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListChart.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListChart.java index 9235b763da..99aac7e3f0 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListChart.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListChart.java @@ -5,7 +5,7 @@ */ package org.sleuthkit.autopsy.timeline.ui.listvew; -import java.util.List; +import java.util.Collection; import javafx.beans.binding.Bindings; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.value.ObservableValue; @@ -43,16 +43,30 @@ class ListChart extends BorderPane implements TimeLineChart { @FXML private TableView table; - Callback, ObservableValue> cellValueFactory = param -> new SimpleObjectProperty<>(param.getValue()); + private static final Callback, ObservableValue> CELL_VALUE_FACTORY = param -> new SimpleObjectProperty<>(param.getValue()); private final TimeLineController controller; - private final TableColumn idColumn = new TableColumn<>("Event ID"); - private final TableColumn millisColumn = new TableColumn<>("Date/Time"); - private final TableColumn iconColumn = new TableColumn<>("Icon"); - private final TableColumn descriptionColumn = new TableColumn<>("Description"); - private final TableColumn baseTypeColumn = new TableColumn<>("Base Type"); - private final TableColumn subTypeColumn = new TableColumn<>("Sub Type"); - private final TableColumn knownColumn = new TableColumn<>("Known"); + + @FXML + private TableColumn idColumn; + + @FXML + private TableColumn millisColumn; + + @FXML + private TableColumn iconColumn; + + @FXML + private TableColumn descriptionColumn; + + @FXML + private TableColumn baseTypeColumn; + + @FXML + private TableColumn subTypeColumn; + + @FXML + private TableColumn knownColumn; ListChart(TimeLineController controller) { this.controller = controller; @@ -71,26 +85,27 @@ class ListChart extends BorderPane implements TimeLineChart { assert subTypeColumn != null : "fx:id=\"subTypeColumn\" was not injected: check your FXML file 'ListViewPane.fxml'."; assert knownColumn != null : "fx:id=\"knownColumn\" was not injected: check your FXML file 'ListViewPane.fxml'."; -// setRowFactory(tableView -> new EventRow()); - idColumn.setCellValueFactory(cellValueFactory); + table.setRowFactory(tableView -> new EventRow()); + idColumn.setCellValueFactory(CELL_VALUE_FACTORY); - millisColumn.setCellValueFactory(cellValueFactory); + millisColumn.setCellValueFactory(CELL_VALUE_FACTORY); millisColumn.setCellFactory(col -> new EpochMillisCell()); - iconColumn.setCellValueFactory(cellValueFactory); + iconColumn.setCellValueFactory(CELL_VALUE_FACTORY); iconColumn.setCellFactory(col -> new ImageCell()); - descriptionColumn.setCellValueFactory(cellValueFactory); + descriptionColumn.setCellValueFactory(CELL_VALUE_FACTORY); descriptionColumn.setCellFactory(col -> new DescriptionCell()); - baseTypeColumn.setCellValueFactory(cellValueFactory); + baseTypeColumn.setCellValueFactory(CELL_VALUE_FACTORY); baseTypeColumn.setCellFactory(col -> new BaseTypeCell()); - subTypeColumn.setCellValueFactory(cellValueFactory); + subTypeColumn.setCellValueFactory(CELL_VALUE_FACTORY); subTypeColumn.setCellFactory(col -> new EventTypeCell()); - knownColumn.setCellValueFactory(cellValueFactory); + knownColumn.setCellValueFactory(CELL_VALUE_FACTORY); knownColumn.setCellFactory(col -> new KnownCell()); + eventCountLabel.textProperty().bind(Bindings.size(table.getItems()).asString().concat(" events")); } @@ -146,7 +161,7 @@ class ListChart extends BorderPane implements TimeLineChart { } @ThreadConfined(type = ThreadConfined.ThreadType.JFX) - void setEventIDs(List eventIDs) { + void setEventIDs(Collection eventIDs) { table.getItems().setAll(eventIDs); } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewChart.fxml b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewChart.fxml index f3b45572c2..87dfee3f19 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewChart.fxml +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewChart.fxml @@ -8,7 +8,7 @@ - + @@ -23,13 +23,13 @@
- - + - + - - + + + diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewPane.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewPane.java index aa6468298d..363f734d4a 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewPane.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewPane.java @@ -8,15 +8,11 @@ package org.sleuthkit.autopsy.timeline.ui.listvew; import java.util.List; import javafx.application.Platform; import javafx.concurrent.Task; -import javafx.scene.Node; import javafx.scene.Parent; -import javafx.scene.chart.Axis; import org.joda.time.Interval; import org.sleuthkit.autopsy.timeline.TimeLineController; import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel; -import org.sleuthkit.autopsy.timeline.datamodel.SingleEvent; -import org.sleuthkit.autopsy.timeline.ui.AbstractVisualizationPane; -import org.sleuthkit.autopsy.timeline.ui.TimeLineView; +import org.sleuthkit.autopsy.timeline.ui.AbstractTimeLineView; /** * @param The type of data plotted along the x axis @@ -33,7 +29,9 @@ import org.sleuthkit.autopsy.timeline.ui.TimeLineView; * public abstract class AbstractVisualizationPane> extends BorderPane { */ -public class ListViewPane extends AbstractVisualizationPane implements TimeLineView { +public class ListViewPane extends AbstractTimeLineView { + + private final ListChart listChart; /** * Constructor @@ -42,55 +40,21 @@ public class ListViewPane extends AbstractVisualizationPane getNewUpdateTask() { return new ListUpdateTask(); } @Override - protected String getTickMarkLabel(Long tickValue) { - return ""; - } - - @Override - protected double getTickSpacing() { - return 0; - } - - @Override - protected Axis getXAxis() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - protected Axis getYAxis() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - protected double getAxisMargin() { - return 0; - } - - @Override - protected void clearChartData() { - getChart().clear(); + protected void clearData() { + listChart.clear(); } private static class ListViewSettingsPane extends Parent { @@ -99,7 +63,7 @@ public class ListViewPane extends AbstractVisualizationPane { + private class ListUpdateTask extends ViewRefreshTask { ListUpdateTask() { super("List update task", true); @@ -114,12 +78,12 @@ public class ListViewPane extends AbstractVisualizationPane eventIDs = eventsModel.getEventIDs(); - Platform.runLater(() -> getChart().setEventIDs(eventIDs)); + Platform.runLater(() -> listChart.setEventIDs(eventIDs)); updateMessage("updating ui"); return eventIDs.isEmpty() == false; @@ -132,9 +96,8 @@ public class ListViewPane extends AbstractVisualizationPane Date: Tue, 17 May 2016 12:21:18 -0400 Subject: [PATCH 019/172] cleanup, remove unneeded interface implementation --- .../timeline/ui/AbstractTimeLineView.java | 19 ++++- .../timeline/ui/listvew/ListChart.java | 71 +++++-------------- .../timeline/ui/listvew/ListViewPane.java | 19 ++++- 3 files changed, 49 insertions(+), 60 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractTimeLineView.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractTimeLineView.java index e890a7387a..cfcb03d001 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractTimeLineView.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractTimeLineView.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2016 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * 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. */ package org.sleuthkit.autopsy.timeline.ui; diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListChart.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListChart.java index 99aac7e3f0..6f01fbbec0 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListChart.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListChart.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2016 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * 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. */ package org.sleuthkit.autopsy.timeline.ui.listvew; @@ -9,33 +22,25 @@ import java.util.Collection; import javafx.beans.binding.Bindings; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.value.ObservableValue; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; import javafx.fxml.FXML; -import javafx.scene.Node; -import javafx.scene.chart.Axis; -import javafx.scene.control.ContextMenu; import javafx.scene.control.Label; import javafx.scene.control.TableCell; import javafx.scene.control.TableColumn; import javafx.scene.control.TableRow; import javafx.scene.control.TableView; import javafx.scene.image.ImageView; -import javafx.scene.input.MouseEvent; import javafx.scene.layout.BorderPane; import javafx.util.Callback; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.timeline.FXMLConstructor; import org.sleuthkit.autopsy.timeline.TimeLineController; import org.sleuthkit.autopsy.timeline.datamodel.SingleEvent; -import org.sleuthkit.autopsy.timeline.ui.IntervalSelector; -import org.sleuthkit.autopsy.timeline.ui.TimeLineChart; import org.sleuthkit.autopsy.timeline.zooming.DescriptionLoD; /** * */ -class ListChart extends BorderPane implements TimeLineChart { +class ListChart extends BorderPane { @FXML private Label eventCountLabel; @@ -109,52 +114,10 @@ class ListChart extends BorderPane implements TimeLineChart { eventCountLabel.textProperty().bind(Bindings.size(table.getItems()).asString().concat(" events")); } - @Override - public ObservableList getSelectedNodes() { - return FXCollections.observableArrayList(); - } - - @Override - public IntervalSelector getIntervalSelector() { - return null; - } - - @Override - public void setIntervalSelector(IntervalSelector newIntervalSelector) { -// throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public IntervalSelector newIntervalSelector() { - return null; - } - - @Override - public void clearIntervalSelector() { -// throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Axis getXAxis() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override public TimeLineController getController() { return controller; } - @Override - public void clearContextMenu() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public ContextMenu getContextMenu(MouseEvent m) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - - } - @ThreadConfined(type = ThreadConfined.ThreadType.JFX) void clear() { table.getItems().clear(); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewPane.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewPane.java index 363f734d4a..6f3fdec60f 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewPane.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewPane.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2016 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * 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. */ package org.sleuthkit.autopsy.timeline.ui.listvew; From 035d35856a727ae3e981d3bdf71af10d96689c4d Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 17 May 2016 12:28:18 -0400 Subject: [PATCH 020/172] VisualizationMode ->ViewMode again --- .../autopsy/timeline/TimeLineController.java | 47 ++++++++++--------- .../timeline/TimeLineTopComponent.java | 30 ++++++------ .../{VisualizationMode.java => ViewMode.java} | 2 +- .../timeline/ui/VisualizationPanel.java | 16 +++---- .../ui/countsview/EventCountsChart.java | 4 +- .../timeline/ui/filtering/FilterSetPanel.java | 6 +-- .../timeline/zooming/ZoomSettingsPane.java | 4 +- 7 files changed, 57 insertions(+), 52 deletions(-) rename Core/src/org/sleuthkit/autopsy/timeline/{VisualizationMode.java => ViewMode.java} (96%) diff --git a/Core/src/org/sleuthkit/autopsy/timeline/TimeLineController.java b/Core/src/org/sleuthkit/autopsy/timeline/TimeLineController.java index bbc213de10..a24a4ef85b 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/TimeLineController.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/TimeLineController.java @@ -199,11 +199,7 @@ public class TimeLineController { private final PropertyChangeListener ingestModuleListener = new AutopsyIngestModuleListener(); @GuardedBy("this") - private final ReadOnlyObjectWrapper visualizationMode = new ReadOnlyObjectWrapper<>(VisualizationMode.COUNTS); - - synchronized public ReadOnlyObjectProperty visualizationModeProperty() { - return visualizationMode.getReadOnlyProperty(); - } + private final ReadOnlyObjectWrapper viewMode = new ReadOnlyObjectWrapper<>(ViewMode.COUNTS); @GuardedBy("filteredEvents") private final FilteredEventsModel filteredEvents; @@ -223,6 +219,13 @@ public class TimeLineController { @GuardedBy("this") private final ObservableList selectedEventIDs = FXCollections.synchronizedObservableList(FXCollections.observableArrayList()); + @GuardedBy("this") + private final ReadOnlyObjectWrapper selectedTimeRange = new ReadOnlyObjectWrapper<>(); + + private final ReadOnlyBooleanWrapper eventsDBStale = new ReadOnlyBooleanWrapper(true); + + private final PromptDialogManager promptDialogManager = new PromptDialogManager(this); + /** * @return A list of the selected event ids */ @@ -230,9 +233,6 @@ public class TimeLineController { return selectedEventIDs; } - @GuardedBy("this") - private final ReadOnlyObjectWrapper selectedTimeRange = new ReadOnlyObjectWrapper<>(); - /** * @return a read only view of the selected interval. */ @@ -282,9 +282,25 @@ public class TimeLineController { synchronized public ReadOnlyBooleanProperty canRetreatProperty() { return historyManager.getCanRetreat(); } - private final ReadOnlyBooleanWrapper eventsDBStale = new ReadOnlyBooleanWrapper(true); - private final PromptDialogManager promptDialogManager = new PromptDialogManager(this); + synchronized public ReadOnlyObjectProperty viewModeProperty() { + return viewMode.getReadOnlyProperty(); + } + + /** + * Set a new ViewMode as the active one. + * + * @param viewMode The new ViewMode to set. + */ + synchronized public void setViewMode(ViewMode viewMode) { + if (this.viewMode.get() != viewMode) { + this.viewMode.set(viewMode); + } + } + + public ViewMode getViewMode() { + return viewMode.get(); + } public TimeLineController(Case autoCase) throws IOException { this.autoCase = autoCase; @@ -582,17 +598,6 @@ public class TimeLineController { pushTimeRange(new Interval(start, end)); } - /** - * Set a new Visualization mode as the active one. - * - * @param visualizationMode The new VisaualizationMode to set. - */ - synchronized public void setVisualizationMode(VisualizationMode visualizationMode) { - if (this.visualizationMode.get() != visualizationMode) { - this.visualizationMode.set(visualizationMode); - } - } - public void selectEventIDs(Collection events) { final LoggedTask selectEventIDsTask = new LoggedTask("Select Event IDs", true) { //NON-NLS @Override diff --git a/Core/src/org/sleuthkit/autopsy/timeline/TimeLineTopComponent.java b/Core/src/org/sleuthkit/autopsy/timeline/TimeLineTopComponent.java index f91d2e8bba..cb4c70b4b6 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/TimeLineTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/TimeLineTopComponent.java @@ -108,13 +108,13 @@ public final class TimeLineTopComponent extends TopComponent implements Explorer final Tab eventsTreeTab = new Tab(Bundle.TimeLineTopComponent_eventsTab_name(), eventsTree); eventsTreeTab.setClosable(false); eventsTreeTab.setGraphic(new ImageView("org/sleuthkit/autopsy/timeline/images/timeline_marker.png")); // NON-NLS - eventsTreeTab.disableProperty().bind(controller.visualizationModeProperty().isEqualTo(VisualizationMode.COUNTS)); + eventsTreeTab.disableProperty().bind(controller.viewModeProperty().isNotEqualTo(ViewMode.DETAIL)); final TabPane leftTabPane = new TabPane(filterTab, eventsTreeTab); VBox.setVgrow(leftTabPane, Priority.ALWAYS); - controller.visualizationModeProperty().addListener((Observable observable) -> { - if (controller.visualizationModeProperty().get().equals(VisualizationMode.COUNTS)) { - //if view mode is counts, make sure events tabd is not active + controller.viewModeProperty().addListener((Observable observable) -> { + if (controller.viewModeProperty().get().equals(ViewMode.DETAIL) == false) { + //if view mode is counts, make sure events tab is not active leftTabPane.getSelectionModel().select(filterTab); } }); @@ -125,7 +125,7 @@ public final class TimeLineTopComponent extends TopComponent implements Explorer final ZoomSettingsPane zoomSettingsPane = new ZoomSettingsPane(controller); - final VBox leftVBox = new VBox(5, timeZonePanel,historyToolBar, zoomSettingsPane, leftTabPane); + final VBox leftVBox = new VBox(5, timeZonePanel, historyToolBar, zoomSettingsPane, leftTabPane); SplitPane.setResizableWithParent(leftVBox, Boolean.FALSE); final SplitPane mainSplitPane = new SplitPane(leftVBox, visualizationPanel); @@ -134,16 +134,16 @@ public final class TimeLineTopComponent extends TopComponent implements Explorer final Scene scene = new Scene(mainSplitPane); scene.addEventFilter(KeyEvent.KEY_PRESSED, (KeyEvent event) -> { - if (new KeyCodeCombination(KeyCode.LEFT, KeyCodeCombination.ALT_DOWN).match(event)) { - new Back(controller).handle(null); - } else if (new KeyCodeCombination(KeyCode.BACK_SPACE).match(event)) { - new Back(controller).handle(null); - } else if (new KeyCodeCombination(KeyCode.RIGHT, KeyCodeCombination.ALT_DOWN).match(event)) { - new Forward(controller).handle(null); - } else if (new KeyCodeCombination(KeyCode.BACK_SPACE, KeyCodeCombination.SHIFT_DOWN).match(event)) { - new Forward(controller).handle(null); - } - }); + if (new KeyCodeCombination(KeyCode.LEFT, KeyCodeCombination.ALT_DOWN).match(event)) { + new Back(controller).handle(null); + } else if (new KeyCodeCombination(KeyCode.BACK_SPACE).match(event)) { + new Back(controller).handle(null); + } else if (new KeyCodeCombination(KeyCode.RIGHT, KeyCodeCombination.ALT_DOWN).match(event)) { + new Forward(controller).handle(null); + } else if (new KeyCodeCombination(KeyCode.BACK_SPACE, KeyCodeCombination.SHIFT_DOWN).match(event)) { + new Forward(controller).handle(null); + } + }); //add ui componenets to JFXPanels jFXVizPanel.setScene(scene); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/VisualizationMode.java b/Core/src/org/sleuthkit/autopsy/timeline/ViewMode.java similarity index 96% rename from Core/src/org/sleuthkit/autopsy/timeline/VisualizationMode.java rename to Core/src/org/sleuthkit/autopsy/timeline/ViewMode.java index c624b1da9d..bbbc3fa11b 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/VisualizationMode.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ViewMode.java @@ -21,7 +21,7 @@ package org.sleuthkit.autopsy.timeline; /** * */ -public enum VisualizationMode { +public enum ViewMode { COUNTS, DETAIL, diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java index 14e92b2998..17d989f04c 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java @@ -72,7 +72,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisCompletedEvent; import org.sleuthkit.autopsy.timeline.FXMLConstructor; import org.sleuthkit.autopsy.timeline.TimeLineController; -import org.sleuthkit.autopsy.timeline.VisualizationMode; +import org.sleuthkit.autopsy.timeline.ViewMode; import org.sleuthkit.autopsy.timeline.actions.Back; import org.sleuthkit.autopsy.timeline.actions.ResetFilters; import org.sleuthkit.autopsy.timeline.actions.SaveSnapshotAsReport; @@ -284,18 +284,18 @@ final public class VisualizationPanel extends BorderPane { detailsToggle.setText(Bundle.VisualizationPanel_detailsToggle_text()); listToggle.setText(Bundle.VisualizationPanel_listToggle_text()); - ToggleGroupValue visModeToggleGroup = new ToggleGroupValue<>(); - visModeToggleGroup.add(listToggle, VisualizationMode.LIST); - visModeToggleGroup.add(detailsToggle, VisualizationMode.DETAIL); - visModeToggleGroup.add(countsToggle, VisualizationMode.COUNTS); + ToggleGroupValue visModeToggleGroup = new ToggleGroupValue<>(); + visModeToggleGroup.add(listToggle, ViewMode.LIST); + visModeToggleGroup.add(detailsToggle, ViewMode.DETAIL); + visModeToggleGroup.add(countsToggle, ViewMode.COUNTS); modeSegButton.setToggleGroup(visModeToggleGroup); visModeToggleGroup.valueProperty().addListener((observable, oldVisMode, newValue) -> { - controller.setVisualizationMode(newValue != null ? newValue : (oldVisMode != null ? oldVisMode : VisualizationMode.COUNTS)); + controller.setViewMode(newValue != null ? newValue : (oldVisMode != null ? oldVisMode : ViewMode.COUNTS)); }); - controller.visualizationModeProperty().addListener(visualizationMode -> syncVisualizationMode()); + controller.viewModeProperty().addListener(visualizationMode -> syncVisualizationMode()); syncVisualizationMode(); ActionUtils.configureButton(new SaveSnapshotAsReport(controller, notificationPane::getContent), snapShotButton); @@ -581,7 +581,7 @@ final public class VisualizationPanel extends BorderPane { */ private void syncVisualizationMode() { AbstractTimeLineView vizPane; - VisualizationMode visMode = controller.visualizationModeProperty().get(); + ViewMode visMode = controller.viewModeProperty().get(); //make new visualization. switch (visMode) { diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/EventCountsChart.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/EventCountsChart.java index 031101ab1e..84502d62f4 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/EventCountsChart.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/EventCountsChart.java @@ -47,7 +47,7 @@ import org.joda.time.Seconds; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.ColorUtilities; import org.sleuthkit.autopsy.timeline.TimeLineController; -import org.sleuthkit.autopsy.timeline.VisualizationMode; +import org.sleuthkit.autopsy.timeline.ViewMode; import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel; import org.sleuthkit.autopsy.timeline.datamodel.eventtype.EventType; import org.sleuthkit.autopsy.timeline.datamodel.eventtype.RootEventType; @@ -403,7 +403,7 @@ final class EventCountsChart extends StackedBarChart implements Bundle.CountsViewPane_detailSwitchMessage(), Bundle.CountsViewPane_detailSwitchTitle(), JOptionPane.YES_NO_OPTION); if (showConfirmDialog == JOptionPane.YES_OPTION) { - controller.setVisualizationMode(VisualizationMode.DETAIL); + controller.setViewMode(ViewMode.DETAIL); } /* diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/FilterSetPanel.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/FilterSetPanel.java index d7168013ca..819a7998de 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/FilterSetPanel.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/FilterSetPanel.java @@ -41,7 +41,7 @@ import org.controlsfx.control.action.ActionUtils; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.timeline.FXMLConstructor; import org.sleuthkit.autopsy.timeline.TimeLineController; -import org.sleuthkit.autopsy.timeline.VisualizationMode; +import org.sleuthkit.autopsy.timeline.ViewMode; import org.sleuthkit.autopsy.timeline.actions.ResetFilters; import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel; import org.sleuthkit.autopsy.timeline.filters.AbstractFilter; @@ -129,9 +129,9 @@ final public class FilterSetPanel extends BorderPane { hiddenDescriptionsListView.setItems(controller.getQuickHideFilters()); hiddenDescriptionsListView.setCellFactory(listView -> getNewDiscriptionFilterListCell()); - controller.visualizationModeProperty().addListener(observable -> { + controller.viewModeProperty().addListener(observable -> { applyFilters(); - if (controller.visualizationModeProperty().get() == VisualizationMode.COUNTS) { + if (controller.viewModeProperty().get() == ViewMode.COUNTS) { dividerPosition = splitPane.getDividerPositions()[0]; splitPane.setDividerPositions(1); hiddenDescriptionsPane.setExpanded(false); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/zooming/ZoomSettingsPane.java b/Core/src/org/sleuthkit/autopsy/timeline/zooming/ZoomSettingsPane.java index 9877150e8b..800c132f8d 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/zooming/ZoomSettingsPane.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/zooming/ZoomSettingsPane.java @@ -31,7 +31,7 @@ import javafx.util.StringConverter; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.timeline.FXMLConstructor; import org.sleuthkit.autopsy.timeline.TimeLineController; -import org.sleuthkit.autopsy.timeline.VisualizationMode; +import org.sleuthkit.autopsy.timeline.ViewMode; import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel; import org.sleuthkit.autopsy.timeline.utils.RangeDivisionInfo; @@ -102,7 +102,7 @@ public class ZoomSettingsPane extends TitledPane { Function.identity()); descrLODLabel.setText(Bundle.ZoomSettingsPane_descrLODLabel_text()); //the description slider is only usefull in the detail view - descrLODSlider.disableProperty().bind(controller.visualizationModeProperty().isEqualTo(VisualizationMode.COUNTS)); + descrLODSlider.disableProperty().bind(controller.viewModeProperty().isEqualTo(ViewMode.COUNTS)); /** * In order for the selected value in the time unit slider to correspond From affc212b893f99ed68435353c9d930ecf03ded05 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 17 May 2016 12:28:18 -0400 Subject: [PATCH 021/172] disable unneeded ui elements when list mode is selected --- .../timeline/TimeLineTopComponent.java | 5 +- .../timeline/ui/VisualizationPanel.java | 72 ++++++++++--------- .../timeline/ui/filtering/FilterSetPanel.java | 30 ++++---- .../timeline/zooming/ZoomSettingsPane.java | 4 +- 4 files changed, 62 insertions(+), 49 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/timeline/TimeLineTopComponent.java b/Core/src/org/sleuthkit/autopsy/timeline/TimeLineTopComponent.java index cb4c70b4b6..5ab8584112 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/TimeLineTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/TimeLineTopComponent.java @@ -22,7 +22,6 @@ import java.awt.BorderLayout; import java.util.Collections; import java.util.List; import javafx.application.Platform; -import javafx.beans.Observable; import javafx.embed.swing.JFXPanel; import javafx.scene.Scene; import javafx.scene.control.SplitPane; @@ -112,8 +111,8 @@ public final class TimeLineTopComponent extends TopComponent implements Explorer final TabPane leftTabPane = new TabPane(filterTab, eventsTreeTab); VBox.setVgrow(leftTabPane, Priority.ALWAYS); - controller.viewModeProperty().addListener((Observable observable) -> { - if (controller.viewModeProperty().get().equals(ViewMode.DETAIL) == false) { + controller.viewModeProperty().addListener(viewMode -> { + if (controller.getViewMode().equals(ViewMode.DETAIL) == false) { //if view mode is counts, make sure events tab is not active leftTabPane.getSelectionModel().select(filterTab); } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java index 17d989f04c..7176440656 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java @@ -91,8 +91,8 @@ import org.sleuthkit.autopsy.timeline.ui.listvew.ListViewPane; import org.sleuthkit.autopsy.timeline.utils.RangeDivisionInfo; /** - * A container for an AbstractVisualizationPane. Has a Toolbar on top to hold - * settings widgets supplied by contained AbstractVisualizationPane, and the + * A container for an AbstractTimelineView. Has a Toolbar on top to hold + * settings widgets supplied by contained AbstractTimelineView, and the * histogram / time selection on bottom. * * TODO: Refactor common code out of histogram and CountsView? -jm @@ -121,7 +121,7 @@ final public class VisualizationPanel extends BorderPane { private LoggedTask histogramTask; private final EventsTree eventsTree; - private AbstractTimeLineView visualization; + private AbstractTimeLineView hostedView; /* * HBox that contains the histogram bars. @@ -295,8 +295,8 @@ final public class VisualizationPanel extends BorderPane { controller.setViewMode(newValue != null ? newValue : (oldVisMode != null ? oldVisMode : ViewMode.COUNTS)); }); - controller.viewModeProperty().addListener(visualizationMode -> syncVisualizationMode()); - syncVisualizationMode(); + controller.viewModeProperty().addListener(viewMode -> syncViewMode()); + syncViewMode(); ActionUtils.configureButton(new SaveSnapshotAsReport(controller, notificationPane::getContent), snapShotButton); ActionUtils.configureButton(new UpdateDB(controller), updateDBButton); @@ -326,7 +326,7 @@ final public class VisualizationPanel extends BorderPane { rangeHistogramStack.getChildren().add(rangeSlider); /* - * this padding attempts to compensates for the fact that the + * This padding attempts to compensates for the fact that the * rangeslider track doesn't extend to edge of node,and so the * histrogram doesn't quite line up with the rangeslider */ @@ -372,7 +372,7 @@ final public class VisualizationPanel extends BorderPane { */ @Subscribe public void handleTimeLineTagUpdate(TagsUpdatedEvent event) { - visualization.setOutOfDate(); + hostedView.setOutOfDate(); Platform.runLater(() -> { if (notificationPane.isShowing() == false) { notificationPane.getActions().setAll(new Refresh()); @@ -410,7 +410,7 @@ final public class VisualizationPanel extends BorderPane { */ @Subscribe public void handleDBUpdated(DBUpdatedEvent event) { - visualization.refresh(); + hostedView.refresh(); refreshHistorgram(); Platform.runLater(notificationPane::hide); } @@ -576,22 +576,28 @@ final public class VisualizationPanel extends BorderPane { } /** - * Switch to the given VisualizationMode, by swapping out the hosted - * AbstractVislualization for one of the correct type. + * Switch to the given ViewMode, by swapping out the hosted + * AbstractTimelineView for one of the correct type. */ - private void syncVisualizationMode() { - AbstractTimeLineView vizPane; - ViewMode visMode = controller.viewModeProperty().get(); + private void syncViewMode() { + AbstractTimeLineView view; + ViewMode viewMode = controller.viewModeProperty().get(); //make new visualization. - switch (visMode) { + switch (viewMode) { case LIST: - vizPane = new ListViewPane(controller); - Platform.runLater(() -> listToggle.setSelected(true)); + view = new ListViewPane(controller); + Platform.runLater(() -> { + listToggle.setSelected(true); + //TODO: should remove listeners from events tree + }); break; case COUNTS: - vizPane = new CountsViewPane(controller); - Platform.runLater(() -> countsToggle.setSelected(true)); + view = new CountsViewPane(controller); + Platform.runLater(() -> { + countsToggle.setSelected(true); + //TODO: should remove listeners from events tree + }); break; case DETAIL: DetailViewPane detailViewPane = new DetailViewPane(controller); @@ -600,34 +606,34 @@ final public class VisualizationPanel extends BorderPane { detailViewPane.setHighLightedEvents(eventsTree.getSelectedEvents()); eventsTree.setDetailViewPane(detailViewPane); }); - vizPane = detailViewPane; + view = detailViewPane; break; default: - throw new IllegalArgumentException("Unknown VisualizationMode: " + visMode.toString()); + throw new IllegalArgumentException("Unknown VisualizationMode: " + viewMode.toString()); } //Set the new AbstractVisualizationPane as the one hosted by this VisualizationPanel. Platform.runLater(() -> { //clear out old vis. - if (visualization != null) { - toolBar.getItems().removeAll(visualization.getSettingsNodes()); - visualization.dispose(); + if (hostedView != null) { + toolBar.getItems().removeAll(hostedView.getSettingsNodes()); + hostedView.dispose(); } - visualization = vizPane; + hostedView = view; //setup new vis. ActionUtils.configureButton(new Refresh(), refreshButton);//configure new refresh action for new visualization - visualization.refresh(); - toolBar.getItems().addAll(2, vizPane.getSettingsNodes()); - notificationPane.setContent(visualization); + hostedView.refresh(); + toolBar.getItems().addAll(2, view.getSettingsNodes()); + notificationPane.setContent(hostedView); //listen to has events property and show "dialog" if it is false. - visualization.hasVisibleEventsProperty().addListener(hasEvents -> { - notificationPane.setContent(visualization.hasVisibleEvents() - ? visualization - : new StackPane(visualization, + hostedView.hasVisibleEventsProperty().addListener(hasEvents -> { + notificationPane.setContent(hostedView.hasVisibleEvents() + ? hostedView + : new StackPane(hostedView, NO_EVENTS_BACKGROUND, - new NoEventsDialog(() -> notificationPane.setContent(visualization)) + new NoEventsDialog(() -> notificationPane.setContent(hostedView)) ) ); }); @@ -773,7 +779,7 @@ final public class VisualizationPanel extends BorderPane { setLongText(Bundle.VisualizationPanel_refresh_longText()); setGraphic(new ImageView(REFRESH)); setEventHandler(actionEvent -> filteredEvents.postRefreshRequest()); - disabledProperty().bind(visualization.outOfDateProperty().not()); + disabledProperty().bind(hostedView.outOfDateProperty().not()); } } } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/FilterSetPanel.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/FilterSetPanel.java index 819a7998de..c1db261b2f 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/FilterSetPanel.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/FilterSetPanel.java @@ -131,18 +131,24 @@ final public class FilterSetPanel extends BorderPane { controller.viewModeProperty().addListener(observable -> { applyFilters(); - if (controller.viewModeProperty().get() == ViewMode.COUNTS) { - dividerPosition = splitPane.getDividerPositions()[0]; - splitPane.setDividerPositions(1); - hiddenDescriptionsPane.setExpanded(false); - hiddenDescriptionsPane.setCollapsible(false); - hiddenDescriptionsPane.setDisable(true); - } else { - splitPane.setDividerPositions(dividerPosition); - hiddenDescriptionsPane.setDisable(false); - hiddenDescriptionsPane.setCollapsible(true); - hiddenDescriptionsPane.setExpanded(true); - hiddenDescriptionsPane.setCollapsible(false); + switch (controller.getViewMode()) { + case COUNTS: + case LIST: + dividerPosition = splitPane.getDividerPositions()[0]; + splitPane.setDividerPositions(1); + hiddenDescriptionsPane.setExpanded(false); + hiddenDescriptionsPane.setCollapsible(false); + hiddenDescriptionsPane.setDisable(true); + break; + case DETAIL: + splitPane.setDividerPositions(dividerPosition); + hiddenDescriptionsPane.setDisable(false); + hiddenDescriptionsPane.setCollapsible(true); + hiddenDescriptionsPane.setExpanded(true); + hiddenDescriptionsPane.setCollapsible(false); + break; + default: + throw new UnsupportedOperationException("Unknown ViewMode: " + controller.getViewMode()); } }); } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/zooming/ZoomSettingsPane.java b/Core/src/org/sleuthkit/autopsy/timeline/zooming/ZoomSettingsPane.java index 800c132f8d..1b783a6e3d 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/zooming/ZoomSettingsPane.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/zooming/ZoomSettingsPane.java @@ -92,6 +92,7 @@ public class ZoomSettingsPane extends TitledPane { EventTypeZoomLevel::ordinal, Function.identity()); typeZoomLabel.setText(Bundle.ZoomSettingsPane_typeZoomLabel_text()); + typeZoomSlider.disableProperty().bind(controller.viewModeProperty().isEqualTo(ViewMode.LIST)); descrLODSlider.setMax(DescriptionLoD.values().length - 1); configureSliderListeners(descrLODSlider, @@ -102,7 +103,7 @@ public class ZoomSettingsPane extends TitledPane { Function.identity()); descrLODLabel.setText(Bundle.ZoomSettingsPane_descrLODLabel_text()); //the description slider is only usefull in the detail view - descrLODSlider.disableProperty().bind(controller.viewModeProperty().isEqualTo(ViewMode.COUNTS)); + descrLODSlider.disableProperty().bind(controller.viewModeProperty().isNotEqualTo(ViewMode.DETAIL)); /** * In order for the selected value in the time unit slider to correspond @@ -121,6 +122,7 @@ public class ZoomSettingsPane extends TitledPane { modelTimeRange -> RangeDivisionInfo.getRangeDivisionInfo(modelTimeRange).getPeriodSize().ordinal() - 1, index -> index + 1); //compensate for the -1 above when mapping to the Enum whose displayName will be shown at index timeUnitLabel.setText(Bundle.ZoomSettingsPane_timeUnitLabel_text()); + timeUnitSlider.disableProperty().bind(controller.viewModeProperty().isEqualTo(ViewMode.LIST)); } /** From f82ec3aa8d4666506fc3b25e7f97b13a266aad91 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 17 May 2016 13:34:50 -0400 Subject: [PATCH 022/172] remove ResultTable when ViewMode.List is active --- .../timeline/TimeLineTopComponent.java | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/timeline/TimeLineTopComponent.java b/Core/src/org/sleuthkit/autopsy/timeline/TimeLineTopComponent.java index 5ab8584112..c116279ee5 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/TimeLineTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/TimeLineTopComponent.java @@ -22,6 +22,7 @@ import java.awt.BorderLayout; import java.util.Collections; import java.util.List; import javafx.application.Platform; +import javafx.beans.Observable; import javafx.embed.swing.JFXPanel; import javafx.scene.Scene; import javafx.scene.control.SplitPane; @@ -33,6 +34,7 @@ import javafx.scene.input.KeyCodeCombination; import javafx.scene.input.KeyEvent; import javafx.scene.layout.Priority; import javafx.scene.layout.VBox; +import javax.swing.SwingUtilities; import org.openide.explorer.ExplorerManager; import org.openide.explorer.ExplorerUtils; import org.openide.util.NbBundle; @@ -86,10 +88,34 @@ public final class TimeLineTopComponent extends TopComponent implements Explorer dataContentPanel = DataContentPanel.createInstance(); this.contentViewerContainerPanel.add(dataContentPanel, BorderLayout.CENTER); tlrv = new TimeLineResultView(controller, dataContentPanel); - DataResultPanel dataResultPanel = tlrv.getDataResultPanel(); + final DataResultPanel dataResultPanel = tlrv.getDataResultPanel(); this.resultContainerPanel.add(dataResultPanel, BorderLayout.CENTER); dataResultPanel.open(); customizeFXComponents(); + + controller.viewModeProperty().addListener((Observable observable) -> { + switch (controller.getViewMode()) { + case COUNTS: + case DETAIL: + SwingUtilities.invokeLater(() -> { + splitYPane.remove(contentViewerContainerPanel); + if ((lowerSplitXPane.getParent() == splitYPane) == false) { + splitYPane.add(lowerSplitXPane); + lowerSplitXPane.add(contentViewerContainerPanel); + } + }); + break; + case LIST: + SwingUtilities.invokeLater(() -> { + splitYPane.remove(lowerSplitXPane); + splitYPane.add(contentViewerContainerPanel); + dataResultPanel.setNode(null); + }); + break; + default: + throw new UnsupportedOperationException("Unknown ViewMode: " + controller.getViewMode()); + } + }); } @NbBundle.Messages({"TimeLineTopComponent.eventsTab.name=Events", @@ -147,7 +173,6 @@ public final class TimeLineTopComponent extends TopComponent implements Explorer //add ui componenets to JFXPanels jFXVizPanel.setScene(scene); jFXstatusPanel.setScene(new Scene(new StatusBar(controller))); - }); } From 738c446d1c693917a5f491adc40e3b922fd55ab9 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Tue, 17 May 2016 13:47:16 -0400 Subject: [PATCH 023/172] Worked towards cancellation policy. --- .../keywordsearch/HtmlTextExtractor.java | 7 +++---- .../KeywordSearchIngestModule.java | 18 +++++++++--------- .../keywordsearch/StringsTextExtractor.java | 12 +++++++++--- .../keywordsearch/TikaTextExtractor.java | 16 +++++++--------- 4 files changed, 28 insertions(+), 25 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HtmlTextExtractor.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HtmlTextExtractor.java index 4e03038b39..0367397137 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HtmlTextExtractor.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HtmlTextExtractor.java @@ -28,6 +28,7 @@ import java.util.Map; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.StringExtract.StringExtractUnicodeTable.SCRIPT; +import org.sleuthkit.autopsy.ingest.IngestJobContext; import org.sleuthkit.autopsy.keywordsearch.Ingester.IngesterException; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.ReadContentInputStream; @@ -48,7 +49,6 @@ class HtmlTextExtractor implements TextExtractor { private static final int MAX_SIZE = 50000000; //private static final String UTF16BOM = "\uFEFF"; disabled prepending of BOM private final char[] textChunkBuf = new char[MAX_EXTR_TEXT_CHARS]; - private KeywordSearchIngestModule module; private AbstractFile sourceFile; private int numChunks = 0; @@ -63,8 +63,7 @@ class HtmlTextExtractor implements TextExtractor { //"application/xml-dtd", ); - HtmlTextExtractor(KeywordSearchIngestModule module) { - this.module = module; + HtmlTextExtractor() { ingester = Server.getIngester(); } @@ -98,7 +97,7 @@ class HtmlTextExtractor implements TextExtractor { } @Override - public boolean index(AbstractFile sourceFile) throws IngesterException { + public boolean index(AbstractFile sourceFile, IngestJobContext context) throws IngesterException { this.sourceFile = sourceFile; numChunks = 0; //unknown until indexing is done diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java index 10f43b4534..5795368e3c 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java @@ -206,14 +206,14 @@ public final class KeywordSearchIngestModule implements FileIngestModule { } //initialize extractors - stringExtractor = new StringsTextExtractor(this); + stringExtractor = new StringsTextExtractor(); stringExtractor.setScripts(KeywordSearchSettings.getStringExtractScripts()); stringExtractor.setOptions(KeywordSearchSettings.getStringExtractOptions()); textExtractors = new ArrayList<>(); //order matters, more specific extractors first - textExtractors.add(new HtmlTextExtractor(this)); - textExtractors.add(new TikaTextExtractor(this)); + textExtractors.add(new HtmlTextExtractor()); + textExtractors.add(new TikaTextExtractor()); indexer = new Indexer(); initialized = true; @@ -417,7 +417,7 @@ public final class KeywordSearchIngestModule implements FileIngestModule { //logger.log(Level.INFO, "Extractor: " + fileExtract + ", file: " + aFile.getName()); //divide into chunks and index - return fileExtract.index(aFile); + return fileExtract.index(aFile, context); } /** @@ -496,9 +496,9 @@ public final class KeywordSearchIngestModule implements FileIngestModule { return; } - String detectedFormat; + String fileType; try { - detectedFormat = fileTypeDetector.getFileType(aFile); + fileType = fileTypeDetector.getFileType(aFile); } catch (TskCoreException ex) { logger.log(Level.SEVERE, String.format("Could not detect format using fileTypeDetector for file: %s", aFile), ex); //NON-NLS return; @@ -506,7 +506,7 @@ public final class KeywordSearchIngestModule implements FileIngestModule { // we skip archive formats that are opened by the archive module. // @@@ We could have a check here to see if the archive module was enabled though... - if (TextExtractor.ARCHIVE_MIME_TYPES.contains(detectedFormat)) { + if (TextExtractor.ARCHIVE_MIME_TYPES.contains(fileType)) { try { ingester.ingest(aFile, false); //meta-data only putIngestStatus(jobId, aFile.getId(), IngestStatus.METADATA_INGESTED); @@ -518,11 +518,11 @@ public final class KeywordSearchIngestModule implements FileIngestModule { } boolean wasTextAdded = false; - if (isTextExtractSupported(aFile, detectedFormat)) { + if (isTextExtractSupported(aFile, fileType)) { //extract text with one of the extractors, divide into chunks and index with Solr try { //logger.log(Level.INFO, "indexing: " + aFile.getName()); - if (!extractTextAndIndex(aFile, detectedFormat)) { + if (!extractTextAndIndex(aFile, fileType)) { logger.log(Level.WARNING, "Failed to extract text and ingest, file ''{0}'' (id: {1}).", new Object[]{aFile.getName(), aFile.getId()}); //NON-NLS putIngestStatus(jobId, aFile.getId(), IngestStatus.SKIPPED_ERROR_TEXTEXTRACT); } else { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/StringsTextExtractor.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/StringsTextExtractor.java index 9b0fd107d0..ce4eeff10f 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/StringsTextExtractor.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/StringsTextExtractor.java @@ -45,7 +45,6 @@ class StringsTextExtractor implements TextExtractor { private static final int BOM_LEN = 0; //disabled prepending of BOM private static final Charset INDEX_CHARSET = Server.DEFAULT_INDEXED_TEXT_CHARSET; private static final SCRIPT DEFAULT_SCRIPT = SCRIPT.LATIN_2; - private KeywordSearchIngestModule module; private AbstractFile sourceFile; private int numChunks = 0; private final List