From 911c7870034a819a6bd7b87b3be80d7b45c0b770 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Fri, 29 Jun 2018 14:32:22 -0400 Subject: [PATCH 001/105] 3964: Functional test include testing flag for zip bomb --- .../autopsy/ingest/EmbeddedFileTest.java | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java index 8f562d698b..a3502c89ac 100755 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java @@ -23,6 +23,7 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; import junit.framework.Test; import org.netbeans.junit.NbModuleSuite; import org.netbeans.junit.NbTestCase; @@ -37,6 +38,7 @@ import org.sleuthkit.autopsy.testutils.CaseUtils; import org.sleuthkit.autopsy.testutils.IngestUtils; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.TskCoreException; /** @@ -45,7 +47,7 @@ import org.sleuthkit.datamodel.TskCoreException; public class EmbeddedFileTest extends NbTestCase { private static final String CASE_NAME = "EmbeddedFileTest"; - private final Path IMAGE_PATH = Paths.get(this.getDataDir().toString(), "EmbeddedIM_img1_v1.vhd"); + private final Path IMAGE_PATH = Paths.get(this.getDataDir().toString(), "new_embedded.vhd"); public static final String HASH_VALUE = "098f6bcd4621d373cade4e832627b4f6"; private static final int DEEP_FOLDER_COUNT = 25; private Case openCase; @@ -92,13 +94,16 @@ public class EmbeddedFileTest extends NbTestCase { CaseUtils.closeCurrentCase(testSucceeded); } - public void testEncryption() { + public void testEncryptionAndZipBomb() { try { List results = openCase.getSleuthkitCase().findAllFilesWhere("name LIKE '%%'"); String protectedName1 = "password_protected.zip"; String protectedName2 = "level1_protected.zip"; String protectedName3 = "42.zip"; - assertEquals(2207, results.size()); + String depthZipBomb = "DepthTriggerZipBomb.zip"; + String ratioZipBomb = "RatioTriggerZipBomb.zip"; + int zipBombs = 0; + assertEquals(2221, results.size()); int passwdProtectedZips = 0; for (AbstractFile file : results) { //.zip file has artifact TSK_ENCRYPTION_DETECTED @@ -109,6 +114,15 @@ public class EmbeddedFileTest extends NbTestCase { assertEquals(artifact.getArtifactTypeID(), BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID()); passwdProtectedZips++; } + } else if (file.getName().equalsIgnoreCase(depthZipBomb) || file.getName().equalsIgnoreCase(ratioZipBomb)){ + ArrayList artifacts = file.getAllArtifacts(); + assertEquals(1, artifacts.size()); + for (BlackboardArtifact artifact : artifacts) { + assertEquals(artifact.getArtifactTypeID(), BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID()); + BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME)); + assertNotNull("Possible Zip Bomb", attribute); + zipBombs++; + } } else {//No other files have artifact defined assertEquals(0, file.getAllArtifacts().size()); } @@ -117,6 +131,8 @@ public class EmbeddedFileTest extends NbTestCase { } //Make sure 3 password protected zip files have been tested: password_protected.zip, level1_protected.zip and 42.zip that we download for bomb testing. assertEquals(3, passwdProtectedZips); + //Make sure 2 zip bomb files have been tested: DepthTriggerZipBomb.zip and RatioTriggerZipBomb.zip. + assertEquals(2, zipBombs); } catch (TskCoreException ex) { Exceptions.printStackTrace(ex); Assert.fail(ex); From 3eaf840a5f50d9ac1cdecda0164be3a97929730d Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Fri, 29 Jun 2018 14:36:44 -0400 Subject: [PATCH 002/105] 3964: correct the image name --- .../src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java index a3502c89ac..24366414d7 100755 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java @@ -47,7 +47,7 @@ import org.sleuthkit.datamodel.TskCoreException; public class EmbeddedFileTest extends NbTestCase { private static final String CASE_NAME = "EmbeddedFileTest"; - private final Path IMAGE_PATH = Paths.get(this.getDataDir().toString(), "new_embedded.vhd"); + private final Path IMAGE_PATH = Paths.get(this.getDataDir().toString(), "EmbeddedIM_img1_v1.vhd"); public static final String HASH_VALUE = "098f6bcd4621d373cade4e832627b4f6"; private static final int DEEP_FOLDER_COUNT = 25; private Case openCase; From 7e37d4cdd25e1c60449612264ec500648095e75b Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Fri, 29 Jun 2018 14:41:34 -0400 Subject: [PATCH 003/105] 3964: rename image name --- .../src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java index 24366414d7..0bb8144527 100755 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java @@ -47,7 +47,7 @@ import org.sleuthkit.datamodel.TskCoreException; public class EmbeddedFileTest extends NbTestCase { private static final String CASE_NAME = "EmbeddedFileTest"; - private final Path IMAGE_PATH = Paths.get(this.getDataDir().toString(), "EmbeddedIM_img1_v1.vhd"); + private final Path IMAGE_PATH = Paths.get(this.getDataDir().toString(), "EmbeddedIM_img2_v1.vhd"); public static final String HASH_VALUE = "098f6bcd4621d373cade4e832627b4f6"; private static final int DEEP_FOLDER_COUNT = 25; private Case openCase; From 91cbc5877437b5ced54a271b0ac99a532cd35d06 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Fri, 29 Jun 2018 15:08:14 -0400 Subject: [PATCH 004/105] 3964: The new vhd file includes the 2 zip bomb test files --- Core/build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/build.xml b/Core/build.xml index f38f7732b2..322fe961ff 100644 --- a/Core/build.xml +++ b/Core/build.xml @@ -86,7 +86,7 @@ - + From 1dc55ba7e8b65a3c86cbdcc6ac5e20dcbe9117f0 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 6 Jul 2018 10:59:38 -0400 Subject: [PATCH 005/105] Implemented message node to handle 'No results found' message. --- .../DataContentViewerOtherCases.form | 4 +- .../DataContentViewerOtherCases.java | 33 +-- ...DataContentViewerOtherCasesTableModel.java | 46 ++-- .../OtherOccurrenceNodeData.java | 213 +--------------- .../OtherOccurrenceNodeInstanceData.java | 233 ++++++++++++++++++ .../OtherOccurrenceNodeMessageData.java | 34 +++ 6 files changed, 319 insertions(+), 244 deletions(-) mode change 100644 => 100755 Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java create mode 100644 Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeInstanceData.java create mode 100755 Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeMessageData.java diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.form b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.form index 60667bae46..7b9e47c236 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.form +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.form @@ -80,7 +80,7 @@ - + @@ -106,7 +106,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java index 8ead475d95..c3558a106b 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java @@ -126,7 +126,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi showCommonalityDetails(); } else if (jmi.equals(addCommentMenuItem)) { try { - OtherOccurrenceNodeData selectedNode = (OtherOccurrenceNodeData) tableModel.getRow(otherCasesTable.getSelectedRow()); + OtherOccurrenceNodeInstanceData selectedNode = (OtherOccurrenceNodeInstanceData) tableModel.getRow(otherCasesTable.getSelectedRow()); AddEditCentralRepoCommentAction action = AddEditCentralRepoCommentAction.createAddEditCommentAction(selectedNode.createCorrelationAttribute()); String currentComment = action.addEditCentralRepoComment(); selectedNode.updateComment(currentComment); @@ -205,7 +205,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi if (-1 != selectedRowViewIdx) { EamDb dbManager = EamDb.getInstance(); int selectedRowModelIdx = otherCasesTable.convertRowIndexToModel(selectedRowViewIdx); - OtherOccurrenceNodeData nodeData = (OtherOccurrenceNodeData) tableModel.getRow(selectedRowModelIdx); + OtherOccurrenceNodeInstanceData nodeData = (OtherOccurrenceNodeInstanceData) tableModel.getRow(selectedRowModelIdx); CorrelationCase eamCasePartial = nodeData.getCorrelationAttributeInstance().getCorrelationCase(); if (eamCasePartial == null) { JOptionPane.showConfirmDialog(showCaseDetailsMenuItem, @@ -504,13 +504,13 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi * * @return A collection of correlated artifact instances */ - private Map getCorrelatedInstances(CorrelationAttribute corAttr, String dataSourceName, String deviceId) { + private Map getCorrelatedInstances(CorrelationAttribute corAttr, String dataSourceName, String deviceId) { // @@@ Check exception try { final Case openCase = Case.getCurrentCase(); String caseUUID = openCase.getName(); - HashMap nodeDataMap = new HashMap<>(); + HashMap nodeDataMap = new HashMap<>(); if (EamDb.isEnabled()) { List instances = EamDb.getInstance().getArtifactInstancesByTypeValue(corAttr.getCorrelationType(), corAttr.getCorrelationValue()); @@ -528,7 +528,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi || !artifactInstance.getCorrelationDataSource().getDeviceID().equals(deviceId) || !artifactInstance.getFilePath().equalsIgnoreCase(file.getParentPath() + file.getName())) { - OtherOccurrenceNodeData newNode = new OtherOccurrenceNodeData(artifactInstance, corAttr.getCorrelationType(), corAttr.getCorrelationValue()); + OtherOccurrenceNodeInstanceData newNode = new OtherOccurrenceNodeInstanceData(artifactInstance, corAttr.getCorrelationType(), corAttr.getCorrelationValue()); UniquePathKey uniquePathKey = new UniquePathKey(newNode); nodeDataMap.put(uniquePathKey, newNode); } @@ -592,9 +592,9 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi * @throws TskCoreException * @throws EamDbException */ - private void addOrUpdateNodeData(final Case autopsyCase, Map nodeDataMap, AbstractFile newFile) throws TskCoreException, EamDbException { + private void addOrUpdateNodeData(final Case autopsyCase, Map nodeDataMap, AbstractFile newFile) throws TskCoreException, EamDbException { - OtherOccurrenceNodeData newNode = new OtherOccurrenceNodeData(newFile, autopsyCase); + OtherOccurrenceNodeInstanceData newNode = new OtherOccurrenceNodeInstanceData(newFile, autopsyCase); // If the caseDB object has a notable tag associated with it, update // the known status to BAD @@ -617,7 +617,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi // Otherwise this is a new node so add the new node to the map. if (nodeDataMap.containsKey(uniquePathKey)) { if (newNode.getKnown() == TskData.FileKnown.BAD) { - OtherOccurrenceNodeData prevInstance = nodeDataMap.get(uniquePathKey); + OtherOccurrenceNodeInstanceData prevInstance = nodeDataMap.get(uniquePathKey); prevInstance.updateKnown(newNode.getKnown()); } } else { @@ -663,8 +663,10 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi * * @param node The node being viewed. */ - @Messages({"DataContentViewerOtherCases.table.isempty=There are no associated artifacts or files from other occurrences to display.", - "DataContentViewerOtherCases.table.noArtifacts=Correlation cannot be performed on the selected file."}) + @Messages({ + "DataContentViewerOtherCases.table.noResultsFound=No results found.", + "DataContentViewerOtherCases.table.noArtifacts=Correlation cannot be performed on the selected file." + }) private void populateTable(Node node) { String dataSourceName = ""; String deviceId = ""; @@ -682,7 +684,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi // get the attributes we can correlate on correlationAttributes.addAll(getCorrelationAttributesFromNode(node)); for (CorrelationAttribute corAttr : correlationAttributes) { - Map correlatedNodeDataMap = new HashMap<>(0); + Map correlatedNodeDataMap = new HashMap<>(0); // get correlation and reference set instances from DB correlatedNodeDataMap.putAll(getCorrelatedInstances(corAttr, dataSourceName, deviceId)); @@ -697,7 +699,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi // @@@ BC: We should have a more descriptive message than this. Mention that the file didn't have a MD5, etc. displayMessageOnTableStatusPanel(Bundle.DataContentViewerOtherCases_table_noArtifacts()); } else if (0 == tableModel.getRowCount()) { - displayMessageOnTableStatusPanel(Bundle.DataContentViewerOtherCases_table_isempty()); + tableModel.addNodeData(new OtherOccurrenceNodeMessageData(Bundle.DataContentViewerOtherCases_table_noResultsFound())); } else { clearMessageOnTableStatusPanel(); setColumnWidths(); @@ -877,8 +879,9 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi if (EamDbUtil.useCentralRepo() && otherCasesTable.getSelectedRowCount() == 1) { int rowIndex = otherCasesTable.getSelectedRow(); OtherOccurrenceNodeData selectedNode = (OtherOccurrenceNodeData) tableModel.getRow(rowIndex); - if (selectedNode.isCentralRepoNode()) { - enableCentralRepoActions = true; + if (selectedNode instanceof OtherOccurrenceNodeInstanceData) { + OtherOccurrenceNodeInstanceData instanceData = (OtherOccurrenceNodeInstanceData) selectedNode; + enableCentralRepoActions = instanceData.isCentralRepoNode(); } } @@ -915,7 +918,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi private final String filePath; private final String type; - UniquePathKey(OtherOccurrenceNodeData nodeData) { + UniquePathKey(OtherOccurrenceNodeInstanceData nodeData) { super(); dataSourceID = nodeData.getDeviceID(); if (nodeData.getFilePath() != null) { diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java index 5febf88dc3..0d7018885c 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java @@ -1,7 +1,7 @@ /* * Central Repository * - * Copyright 2015-2017 Basis Technology Corp. + * Copyright 2015-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,8 +22,6 @@ import java.util.ArrayList; import java.util.List; import javax.swing.table.AbstractTableModel; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute; -import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; /** * Model for cells in data content viewer table @@ -34,7 +32,7 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel { "DataContentViewerOtherCasesTableModel.device=Device", "DataContentViewerOtherCasesTableModel.dataSource=Data Source", "DataContentViewerOtherCasesTableModel.path=Path", - "DataContentViewerOtherCasesTableModel.type=Correlation Type", + "DataContentViewerOtherCasesTableModel.property=Correlation Property", "DataContentViewerOtherCasesTableModel.value=Correlation Value", "DataContentViewerOtherCasesTableModel.known=Known", "DataContentViewerOtherCasesTableModel.comment=Comment", @@ -44,7 +42,7 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel { // If order is changed, update the CellRenderer to ensure correct row coloring. CASE_NAME(Bundle.DataContentViewerOtherCasesTableModel_case(), 100), DATA_SOURCE(Bundle.DataContentViewerOtherCasesTableModel_dataSource(), 100), - TYPE(Bundle.DataContentViewerOtherCasesTableModel_type(), 100), + PROPERTY(Bundle.DataContentViewerOtherCasesTableModel_property(), 125), VALUE(Bundle.DataContentViewerOtherCasesTableModel_value(), 200), KNOWN(Bundle.DataContentViewerOtherCasesTableModel_known(), 50), FILE_PATH(Bundle.DataContentViewerOtherCasesTableModel_path(), 450), @@ -126,38 +124,49 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel { */ private Object mapValueById(int rowIdx, TableColumns colId) { OtherOccurrenceNodeData nodeData = nodeDataList.get(rowIdx); + + if (nodeData instanceof OtherOccurrenceNodeMessageData) { + if (colId == TableColumns.CASE_NAME) { + OtherOccurrenceNodeMessageData messageData = (OtherOccurrenceNodeMessageData) nodeData; + return messageData.getDisplayMessage(); + } else { + return ""; + } + } + + OtherOccurrenceNodeInstanceData instanceData = (OtherOccurrenceNodeInstanceData) nodeData; String value = Bundle.DataContentViewerOtherCasesTableModel_noData(); switch (colId) { case CASE_NAME: - if (null != nodeData.getCaseName()) { - value = nodeData.getCaseName(); + if (null != instanceData.getCaseName()) { + value = instanceData.getCaseName(); } break; case DEVICE: - if (null != nodeData.getDeviceID()) { - value = nodeData.getDeviceID(); + if (null != instanceData.getDeviceID()) { + value = instanceData.getDeviceID(); } break; case DATA_SOURCE: - if (null != nodeData.getDataSourceName()) { - value = nodeData.getDataSourceName(); + if (null != instanceData.getDataSourceName()) { + value = instanceData.getDataSourceName(); } break; case FILE_PATH: - value = nodeData.getFilePath(); + value = instanceData.getFilePath(); break; - case TYPE: - value = nodeData.getType(); + case PROPERTY: + value = instanceData.getType(); break; case VALUE: - value = nodeData.getValue(); + value = instanceData.getValue(); break; case KNOWN: - value = nodeData.getKnown().getName(); + value = instanceData.getKnown().getName(); break; case COMMENT: - value = nodeData.getComment(); + value = instanceData.getComment(); break; } return value; @@ -178,6 +187,9 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel { fireTableDataChanged(); } + /** + * Clear the node data table. + */ void clearTable() { nodeDataList.clear(); fireTableDataChanged(); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java old mode 100644 new mode 100755 index 958068fb14..c10f078313 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java @@ -1,5 +1,5 @@ /* - * Central Repository + * Autopsy Forensic Browser * * Copyright 2018 Basis Technology Corp. * Contact: carrier sleuthkit org @@ -18,216 +18,9 @@ */ package org.sleuthkit.autopsy.centralrepository.contentviewer; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute; -import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; -import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; -import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.DataSource; -import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.datamodel.TskData; -import org.sleuthkit.datamodel.TskDataException; - /** - * Class for populating the Other Occurrences tab + * Marker interface for Other Occurrences nodes. */ -class OtherOccurrenceNodeData { +interface OtherOccurrenceNodeData { - // For now hard code the string for the central repo files type, since - // getting it dynamically can fail. - private static final String FILE_TYPE_STR = "Files"; - - private final String caseName; - private String deviceID; - private String dataSourceName; - private final String filePath; - private final String typeStr; - private final CorrelationAttribute.Type type; - private final String value; - private TskData.FileKnown known; - private String comment; - - private AbstractFile originalAbstractFile = null; - private CorrelationAttributeInstance originalCorrelationInstance = null; - - /** - * Create a node from a central repo instance. - * @param instance The central repo instance - * @param type The type of the instance - * @param value The value of the instance - */ - OtherOccurrenceNodeData(CorrelationAttributeInstance instance, CorrelationAttribute.Type type, String value) { - caseName = instance.getCorrelationCase().getDisplayName(); - deviceID = instance.getCorrelationDataSource().getDeviceID(); - dataSourceName = instance.getCorrelationDataSource().getName(); - filePath = instance.getFilePath(); - this.typeStr = type.getDisplayName(); - this.type = type; - this.value = value; - known = instance.getKnownStatus(); - comment = instance.getComment(); - - originalCorrelationInstance = instance; - } - - /** - * Create a node from an abstract file. - * @param newFile The abstract file - * @param autopsyCase The current case - * @throws EamDbException - */ - OtherOccurrenceNodeData(AbstractFile newFile, Case autopsyCase) throws EamDbException { - caseName = autopsyCase.getDisplayName(); - try { - DataSource dataSource = autopsyCase.getSleuthkitCase().getDataSource(newFile.getDataSource().getId()); - deviceID = dataSource.getDeviceId(); - dataSourceName = dataSource.getName(); - } catch (TskDataException | TskCoreException ex) { - throw new EamDbException("Error loading data source for abstract file ID " + newFile.getId(), ex); - } - - filePath = newFile.getParentPath() + newFile.getName(); - typeStr = FILE_TYPE_STR; - this.type = null; - value = newFile.getMd5Hash(); - known = newFile.getKnown(); - comment = ""; - - originalAbstractFile = newFile; - } - - /** - * Check if this node is a "file" type - * @return true if it is a file type - */ - boolean isFileType() { - return FILE_TYPE_STR.equals(typeStr); - } - - /** - * Update the known status for this node - * @param newKnownStatus The new known status - */ - void updateKnown(TskData.FileKnown newKnownStatus) { - known = newKnownStatus; - } - - /** - * Update the comment for this node - * @param newComment The new comment - */ - void updateComment(String newComment) { - comment = newComment; - } - - /** - * Check if this is a central repo node. - * @return true if this node was created from a central repo instance, false otherwise - */ - boolean isCentralRepoNode() { - return (originalCorrelationInstance != null); - } - - /** - * Uses the saved instance plus type and value to make a new CorrelationAttribute. - * Should only be called if isCentralRepoNode() is true. - * @return the newly created CorrelationAttribute - */ - CorrelationAttribute createCorrelationAttribute() throws EamDbException { - if (! isCentralRepoNode() ) { - throw new EamDbException("Can not create CorrelationAttribute for non central repo node"); - } - CorrelationAttribute attr = new CorrelationAttribute(type, value); - attr.addInstance(originalCorrelationInstance); - return attr; - } - - /** - * Get the case name - * @return the case name - */ - String getCaseName() { - return caseName; - } - - /** - * Get the device ID - * @return the device ID - */ - String getDeviceID() { - return deviceID; - } - - /** - * Get the data source name - * @return the data source name - */ - String getDataSourceName() { - return dataSourceName; - } - - /** - * Get the file path - * @return the file path - */ - String getFilePath() { - return filePath; - } - - /** - * Get the type (as a string) - * @return the type - */ - String getType() { - return typeStr; - } - - /** - * Get the value (MD5 hash for files) - * @return the value - */ - String getValue() { - return value; - } - - /** - * Get the known status - * @return the known status - */ - TskData.FileKnown getKnown() { - return known; - } - - /** - * Get the comment - * @return the comment - */ - String getComment() { - return comment; - } - - /** - * Get the backing abstract file. - * Should only be called if isCentralRepoNode() is false - * @return the original abstract file - */ - AbstractFile getAbstractFile() throws EamDbException { - if (originalCorrelationInstance == null) { - throw new EamDbException("AbstractFile is null"); - } - return originalAbstractFile; - } - - /** - * Get the backing CorrelationAttributeInstance. - * Should only be called if isCentralRepoNode() is true - * @return the original CorrelationAttributeInstance - * @throws EamDbException - */ - CorrelationAttributeInstance getCorrelationAttributeInstance() throws EamDbException { - if (originalCorrelationInstance == null) { - throw new EamDbException("CorrelationAttributeInstance is null"); - } - return originalCorrelationInstance; - } } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeInstanceData.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeInstanceData.java new file mode 100644 index 0000000000..7eb907aba8 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeInstanceData.java @@ -0,0 +1,233 @@ +/* + * Central Repository + * + * Copyright 2018 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.centralrepository.contentviewer; + +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; +import org.sleuthkit.datamodel.TskDataException; + +/** + * Class for populating the Other Occurrences tab + */ +class OtherOccurrenceNodeInstanceData implements OtherOccurrenceNodeData { + + // For now hard code the string for the central repo files type, since + // getting it dynamically can fail. + private static final String FILE_TYPE_STR = "Files"; + + private final String caseName; + private String deviceID; + private String dataSourceName; + private final String filePath; + private final String typeStr; + private final CorrelationAttribute.Type type; + private final String value; + private TskData.FileKnown known; + private String comment; + + private AbstractFile originalAbstractFile = null; + private CorrelationAttributeInstance originalCorrelationInstance = null; + + /** + * Create a node from a central repo instance. + * @param instance The central repo instance + * @param type The type of the instance + * @param value The value of the instance + */ + OtherOccurrenceNodeInstanceData(CorrelationAttributeInstance instance, CorrelationAttribute.Type type, String value) { + caseName = instance.getCorrelationCase().getDisplayName(); + deviceID = instance.getCorrelationDataSource().getDeviceID(); + dataSourceName = instance.getCorrelationDataSource().getName(); + filePath = instance.getFilePath(); + this.typeStr = type.getDisplayName(); + this.type = type; + this.value = value; + known = instance.getKnownStatus(); + comment = instance.getComment(); + + originalCorrelationInstance = instance; + } + + /** + * Create a node from an abstract file. + * @param newFile The abstract file + * @param autopsyCase The current case + * @throws EamDbException + */ + OtherOccurrenceNodeInstanceData(AbstractFile newFile, Case autopsyCase) throws EamDbException { + caseName = autopsyCase.getDisplayName(); + try { + DataSource dataSource = autopsyCase.getSleuthkitCase().getDataSource(newFile.getDataSource().getId()); + deviceID = dataSource.getDeviceId(); + dataSourceName = dataSource.getName(); + } catch (TskDataException | TskCoreException ex) { + throw new EamDbException("Error loading data source for abstract file ID " + newFile.getId(), ex); + } + + filePath = newFile.getParentPath() + newFile.getName(); + typeStr = FILE_TYPE_STR; + this.type = null; + value = newFile.getMd5Hash(); + known = newFile.getKnown(); + comment = ""; + + originalAbstractFile = newFile; + } + + /** + * Check if this node is a "file" type + * @return true if it is a file type + */ + boolean isFileType() { + return FILE_TYPE_STR.equals(typeStr); + } + + /** + * Update the known status for this node + * @param newKnownStatus The new known status + */ + void updateKnown(TskData.FileKnown newKnownStatus) { + known = newKnownStatus; + } + + /** + * Update the comment for this node + * @param newComment The new comment + */ + void updateComment(String newComment) { + comment = newComment; + } + + /** + * Check if this is a central repo node. + * @return true if this node was created from a central repo instance, false otherwise + */ + boolean isCentralRepoNode() { + return (originalCorrelationInstance != null); + } + + /** + * Uses the saved instance plus type and value to make a new CorrelationAttribute. + * Should only be called if isCentralRepoNode() is true. + * @return the newly created CorrelationAttribute + */ + CorrelationAttribute createCorrelationAttribute() throws EamDbException { + if (! isCentralRepoNode() ) { + throw new EamDbException("Can not create CorrelationAttribute for non central repo node"); + } + CorrelationAttribute attr = new CorrelationAttribute(type, value); + attr.addInstance(originalCorrelationInstance); + return attr; + } + + /** + * Get the case name + * @return the case name + */ + String getCaseName() { + return caseName; + } + + /** + * Get the device ID + * @return the device ID + */ + String getDeviceID() { + return deviceID; + } + + /** + * Get the data source name + * @return the data source name + */ + String getDataSourceName() { + return dataSourceName; + } + + /** + * Get the file path + * @return the file path + */ + String getFilePath() { + return filePath; + } + + /** + * Get the type (as a string) + * @return the type + */ + String getType() { + return typeStr; + } + + /** + * Get the value (MD5 hash for files) + * @return the value + */ + String getValue() { + return value; + } + + /** + * Get the known status + * @return the known status + */ + TskData.FileKnown getKnown() { + return known; + } + + /** + * Get the comment + * @return the comment + */ + String getComment() { + return comment; + } + + /** + * Get the backing abstract file. + * Should only be called if isCentralRepoNode() is false + * @return the original abstract file + */ + AbstractFile getAbstractFile() throws EamDbException { + if (originalCorrelationInstance == null) { + throw new EamDbException("AbstractFile is null"); + } + return originalAbstractFile; + } + + /** + * Get the backing CorrelationAttributeInstance. + * Should only be called if isCentralRepoNode() is true + * @return the original CorrelationAttributeInstance + * @throws EamDbException + */ + CorrelationAttributeInstance getCorrelationAttributeInstance() throws EamDbException { + if (originalCorrelationInstance == null) { + throw new EamDbException("CorrelationAttributeInstance is null"); + } + return originalCorrelationInstance; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeMessageData.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeMessageData.java new file mode 100755 index 0000000000..99e530349a --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeMessageData.java @@ -0,0 +1,34 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 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.centralrepository.contentviewer; + +/** + * Class for populating the Other Occurrences tab with a single message. + */ +final class OtherOccurrenceNodeMessageData implements OtherOccurrenceNodeData { + private final String displayMessage; + + OtherOccurrenceNodeMessageData(String displayMessage) { + this.displayMessage = displayMessage; + } + + String getDisplayMessage() { + return displayMessage; + } +} From 3539b6c70e700b5647559dbec1b40ff07fa8f378 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 6 Jul 2018 15:51:53 -0400 Subject: [PATCH 006/105] Renamed menu item; partial implementation of error handling. --- .../AddEditCentralRepoCommentAction.java | 59 ++++--------------- .../CentralRepoCommentDialog.java | 21 +++++-- ...CentralRepoContextMenuActionsProvider.java | 2 +- .../contentviewer/Bundle.properties | 2 +- .../DataContentViewerOtherCases.java | 5 +- 5 files changed, 31 insertions(+), 58 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java b/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java index 654ee7161e..90317ab747 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java @@ -22,36 +22,32 @@ import java.awt.event.ActionEvent; import java.util.logging.Level; import javax.swing.AbstractAction; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute; import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.TskCoreException; /** * An AbstractAction to manage adding and modifying a Central Repository file * instance comment. */ +@Messages({"AddEditCentralRepoCommentAction.menuItemText.addEditCentralRepoComment=Add/Edit Central Repository Comment"}) public final class AddEditCentralRepoCommentAction extends AbstractAction { private static final Logger logger = Logger.getLogger(AddEditCentralRepoCommentAction.class.getName()); private boolean addToDatabase; private CorrelationAttribute correlationAttribute; - String title; /** * Private constructor to create an instance given a CorrelationAttribute. * * @param correlationAttribute The correlation attribute to modify. - * @param title The text for the menu item. */ - private AddEditCentralRepoCommentAction(CorrelationAttribute correlationAttribute, String title) { - super(title); - this.title = title; + public AddEditCentralRepoCommentAction(CorrelationAttribute correlationAttribute) { + super(Bundle.AddEditCentralRepoCommentAction_menuItemText_addEditCentralRepoComment()); this.correlationAttribute = correlationAttribute; } @@ -60,12 +56,9 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction { * * @param file The file from which a correlation attribute to modify is * derived. - * @param title The text for the menu item. */ - private AddEditCentralRepoCommentAction(AbstractFile file, String title) { - - super(title); - this.title = title; + public AddEditCentralRepoCommentAction(AbstractFile file) { + super(Bundle.AddEditCentralRepoCommentAction_menuItemText_addEditCentralRepoComment()); correlationAttribute = EamArtifactUtil.getCorrelationAttributeFromContent(file); if (correlationAttribute == null) { addToDatabase = true; @@ -90,7 +83,7 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction { * @return the current comment for this instance */ public String addEditCentralRepoComment() { - CentralRepoCommentDialog centralRepoCommentDialog = new CentralRepoCommentDialog(correlationAttribute, title); + CentralRepoCommentDialog centralRepoCommentDialog = new CentralRepoCommentDialog(correlationAttribute); centralRepoCommentDialog.display(); if (centralRepoCommentDialog.isCommentUpdated()) { @@ -106,43 +99,11 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction { } } catch (EamDbException ex) { logger.log(Level.SEVERE, "Error adding comment", ex); + //DLG: Create error popup dialog here. + return centralRepoCommentDialog.getOriginalComment(); } } - return centralRepoCommentDialog.getComment(); - } - - /** - * Create an instance labeled "Add/Edit Central Repository Comment" given an - * AbstractFile. This is intended for the result view. - * - * @param file The file from which a correlation attribute to modify is - * derived. - * - * @return The instance. - * - * @throws EamDbException - * @throws NoCurrentCaseException - * @throws TskCoreException - */ - @Messages({"AddEditCentralRepoCommentAction.menuItemText.addEditCentralRepoComment=Add/Edit Central Repository Comment"}) - public static AddEditCentralRepoCommentAction createAddEditCentralRepoCommentAction(AbstractFile file) { - - return new AddEditCentralRepoCommentAction(file, - Bundle.AddEditCentralRepoCommentAction_menuItemText_addEditCentralRepoComment()); - } - - /** - * Create an instance labeled "Add/Edit Comment" given a - * CorrelationAttribute. This is intended for the content view. - * - * @param correlationAttribute The correlation attribute to modify. - * - * @return The instance. - */ - @Messages({"AddEditCentralRepoCommentAction.menuItemText.addEditComment=Add/Edit Comment"}) - public static AddEditCentralRepoCommentAction createAddEditCommentAction(CorrelationAttribute correlationAttribute) { - - return new AddEditCentralRepoCommentAction(correlationAttribute, - Bundle.AddEditCentralRepoCommentAction_menuItemText_addEditComment()); + + return centralRepoCommentDialog.getNewComment(); } } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.java b/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.java index c95b0bfde7..88708be173 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.centralrepository; +import org.openide.util.NbBundle.Messages; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; @@ -26,21 +27,22 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeIns * Dialog to allow Central Repository file instance comments to be added and * modified. */ +@Messages({"CentralRepoCommentDialog.title.addEditCentralRepoComment=Add/Edit Central Repository Comment"}) @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives final class CentralRepoCommentDialog extends javax.swing.JDialog { private final CorrelationAttribute correlationAttribute; private boolean commentUpdated = false; private String currentComment = ""; + private String originalComment = ""; /** * Create an instance. * * @param correlationAttribute The correlation attribute to be modified. - * @param title The title to assign the dialog. */ - CentralRepoCommentDialog(CorrelationAttribute correlationAttribute, String title) { - super(WindowManager.getDefault().getMainWindow(), title); + CentralRepoCommentDialog(CorrelationAttribute correlationAttribute) { + super(WindowManager.getDefault().getMainWindow(), Bundle.CentralRepoCommentDialog_title_addEditCentralRepoComment()); initComponents(); @@ -49,6 +51,7 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog { // Store the original comment if (instance.getComment() != null) { currentComment = instance.getComment(); + originalComment = currentComment; } pathLabel.setText(instance.getFilePath()); @@ -82,11 +85,21 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog { * Get the current comment. * If the user hit OK, this will be the new comment. * If the user canceled, this will be the original comment. + * * @return the comment */ - String getComment() { + String getNewComment() { return currentComment; } + + /** + * Get the original comment. + * + * @return the comment + */ + String getOriginalComment() { + return originalComment; + } /** * This method is called from within the constructor to initialize the form. diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoContextMenuActionsProvider.java b/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoContextMenuActionsProvider.java index 5a6e8fa652..dff9be8f91 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoContextMenuActionsProvider.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoContextMenuActionsProvider.java @@ -47,7 +47,7 @@ public class CentralRepoContextMenuActionsProvider implements ContextMenuActions for (AbstractFile file : selectedFiles) { if (EamDbUtil.useCentralRepo() && EamArtifactUtil.isSupportedAbstractFileType(file) && file.isFile()) { - actions.add(AddEditCentralRepoCommentAction.createAddEditCentralRepoCommentAction(file)); + actions.add(new AddEditCentralRepoCommentAction(file)); } } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/Bundle.properties b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/Bundle.properties index b3375cda0d..acb3fa42d1 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/Bundle.properties @@ -3,7 +3,7 @@ DataContentViewerOtherCases.showCaseDetailsMenuItem.text=Show Case Details DataContentViewerOtherCases.table.toolTip.text=Click column name to sort. Right-click on the table for more options. DataContentViewerOtherCases.exportToCSVMenuItem.text=Export Selected Rows to CSV DataContentViewerOtherCases.showCommonalityMenuItem.text=Show Frequency -DataContentViewerOtherCases.addCommentMenuItem.text=Add/Edit Comment +DataContentViewerOtherCases.addCommentMenuItem.text=Add/Edit Central Repository Comment DataContentViewerOtherCases.earliestCaseDate.text=Earliest Case Date DataContentViewerOtherCases.earliestCaseLabel.toolTipText= DataContentViewerOtherCases.earliestCaseLabel.text=Central Repository Starting Date: diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java index 8ead475d95..2a5a98cd7e 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java @@ -38,7 +38,6 @@ import java.util.Map; import java.util.Objects; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; -import java.util.stream.Collectors; import javax.swing.JFileChooser; import javax.swing.JMenuItem; import javax.swing.JOptionPane; @@ -127,12 +126,12 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi } else if (jmi.equals(addCommentMenuItem)) { try { OtherOccurrenceNodeData selectedNode = (OtherOccurrenceNodeData) tableModel.getRow(otherCasesTable.getSelectedRow()); - AddEditCentralRepoCommentAction action = AddEditCentralRepoCommentAction.createAddEditCommentAction(selectedNode.createCorrelationAttribute()); + AddEditCentralRepoCommentAction action = new AddEditCentralRepoCommentAction(selectedNode.createCorrelationAttribute()); String currentComment = action.addEditCentralRepoComment(); selectedNode.updateComment(currentComment); otherCasesTable.repaint(); } catch (EamDbException ex) { - logger.log(Level.SEVERE, "Error performing Add/Edit Comment action", ex); + logger.log(Level.SEVERE, "Error performing Add/Edit Central Repository Comment action", ex); } } } From 5aec70fbaf03c09630ddba81185a59a5fa13c1fb Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 6 Jul 2018 16:43:56 -0400 Subject: [PATCH 007/105] Partial handling of 'noArtifacts' message. --- .../DataContentViewerOtherCases.java | 25 +++++++------------ ...DataContentViewerOtherCasesTableModel.java | 8 +++--- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java index c3558a106b..ebc5b7c375 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java @@ -38,7 +38,6 @@ import java.util.Map; import java.util.Objects; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; -import java.util.stream.Collectors; import javax.swing.JFileChooser; import javax.swing.JMenuItem; import javax.swing.JOptionPane; @@ -49,6 +48,7 @@ import javax.swing.JPanel; import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; +import javax.swing.table.TableColumnModel; import org.joda.time.DateTimeZone; import org.joda.time.LocalDateTime; import org.openide.nodes.Node; @@ -147,7 +147,6 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi // Set background of every nth row as light grey. TableCellRenderer renderer = new DataContentViewerOtherCasesTableCellRenderer(); otherCasesTable.setDefaultRenderer(Object.class, renderer); - tableStatusPanelLabel.setVisible(false); } @@ -664,8 +663,8 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi * @param node The node being viewed. */ @Messages({ - "DataContentViewerOtherCases.table.noResultsFound=No results found.", - "DataContentViewerOtherCases.table.noArtifacts=Correlation cannot be performed on the selected file." + "DataContentViewerOtherCases.table.noArtifacts=Item has no attributes with which to search.", + "DataContentViewerOtherCases.table.noResultsFound=No results found." }) private void populateTable(Node node) { String dataSourceName = ""; @@ -696,17 +695,20 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi } if (correlationAttributes.isEmpty()) { - // @@@ BC: We should have a more descriptive message than this. Mention that the file didn't have a MD5, etc. - displayMessageOnTableStatusPanel(Bundle.DataContentViewerOtherCases_table_noArtifacts()); + tableModel.addNodeData(new OtherOccurrenceNodeMessageData(Bundle.DataContentViewerOtherCases_table_noArtifacts())); + //DLG: Removing columns causes problems. Look into resizing columns. } else if (0 == tableModel.getRowCount()) { tableModel.addNodeData(new OtherOccurrenceNodeMessageData(Bundle.DataContentViewerOtherCases_table_noResultsFound())); + //DLG: Removing columns causes problems. Look into resizing columns. } else { - clearMessageOnTableStatusPanel(); setColumnWidths(); } setEarliestCaseDate(); } + /** + * Adjust column widths to their preferred values. + */ private void setColumnWidths() { for (int idx = 0; idx < tableModel.getColumnCount(); idx++) { TableColumn column = otherCasesTable.getColumnModel().getColumn(idx); @@ -717,15 +719,6 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi } } - private void displayMessageOnTableStatusPanel(String message) { - tableStatusPanelLabel.setText(message); - tableStatusPanelLabel.setVisible(true); - } - - private void clearMessageOnTableStatusPanel() { - tableStatusPanelLabel.setVisible(false); - } - /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java index 0d7018885c..de528e2d42 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java @@ -32,8 +32,8 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel { "DataContentViewerOtherCasesTableModel.device=Device", "DataContentViewerOtherCasesTableModel.dataSource=Data Source", "DataContentViewerOtherCasesTableModel.path=Path", - "DataContentViewerOtherCasesTableModel.property=Correlation Property", - "DataContentViewerOtherCasesTableModel.value=Correlation Value", + "DataContentViewerOtherCasesTableModel.attribute=Matched Attribute", + "DataContentViewerOtherCasesTableModel.value=Attribute Value", "DataContentViewerOtherCasesTableModel.known=Known", "DataContentViewerOtherCasesTableModel.comment=Comment", "DataContentViewerOtherCasesTableModel.noData=No Data.",}) @@ -42,7 +42,7 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel { // If order is changed, update the CellRenderer to ensure correct row coloring. CASE_NAME(Bundle.DataContentViewerOtherCasesTableModel_case(), 100), DATA_SOURCE(Bundle.DataContentViewerOtherCasesTableModel_dataSource(), 100), - PROPERTY(Bundle.DataContentViewerOtherCasesTableModel_property(), 125), + ATTRIBUTE(Bundle.DataContentViewerOtherCasesTableModel_attribute(), 125), VALUE(Bundle.DataContentViewerOtherCasesTableModel_value(), 200), KNOWN(Bundle.DataContentViewerOtherCasesTableModel_known(), 50), FILE_PATH(Bundle.DataContentViewerOtherCasesTableModel_path(), 450), @@ -156,7 +156,7 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel { case FILE_PATH: value = instanceData.getFilePath(); break; - case PROPERTY: + case ATTRIBUTE: value = instanceData.getType(); break; case VALUE: From 1912be53e56988ecd4502e98d956b8abce33bd7f Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Sat, 7 Jul 2018 00:35:14 -0400 Subject: [PATCH 008/105] Improved error handling. --- .../AddEditCentralRepoCommentAction.java | 47 ++++++++++++------- .../DataContentViewerOtherCases.java | 9 ++-- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java b/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java index 90317ab747..8bca85ac70 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java @@ -21,6 +21,9 @@ package org.sleuthkit.autopsy.centralrepository; import java.awt.event.ActionEvent; import java.util.logging.Level; import javax.swing.AbstractAction; +import org.openide.DialogDisplayer; +import org.openide.NotifyDescriptor; +import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute; import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil; @@ -40,6 +43,7 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction { private boolean addToDatabase; private CorrelationAttribute correlationAttribute; + private String comment; /** * Private constructor to create an instance given a CorrelationAttribute. @@ -54,8 +58,8 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction { /** * Private constructor to create an instance given an AbstractFile. * - * @param file The file from which a correlation attribute to modify is - * derived. + * @param file The file from which a correlation attribute to modify is + * derived. */ public AddEditCentralRepoCommentAction(AbstractFile file) { super(Bundle.AddEditCentralRepoCommentAction_menuItemText_addEditCentralRepoComment()); @@ -66,26 +70,24 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction { } } - @Override - public void actionPerformed(ActionEvent event) { - addEditCentralRepoComment(); - } - /** * Create a Add/Edit dialog for the correlation attribute file instance * comment. The comment will be updated in the database if the file instance * exists there, or a new file instance will be added to the database with * the comment attached otherwise. - * - * The current comment for this instance is returned in case it is needed to - * update the display. * - * @return the current comment for this instance + * The current comment for this instance is is saved in case it is needed to + * update the display. If the comment was not changed either due to the + * action being canceled or the occurrence of an error, the comment will be + * null. */ - public String addEditCentralRepoComment() { + @Override + public void actionPerformed(ActionEvent event) { CentralRepoCommentDialog centralRepoCommentDialog = new CentralRepoCommentDialog(correlationAttribute); centralRepoCommentDialog.display(); + comment = null; + if (centralRepoCommentDialog.isCommentUpdated()) { EamDb dbManager; @@ -97,13 +99,26 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction { } else { dbManager.updateAttributeInstanceComment(correlationAttribute); } + + comment = centralRepoCommentDialog.getNewComment(); } catch (EamDbException ex) { logger.log(Level.SEVERE, "Error adding comment", ex); - //DLG: Create error popup dialog here. - return centralRepoCommentDialog.getOriginalComment(); + NotifyDescriptor notifyDescriptor = new NotifyDescriptor.Message( + "An error occurred while trying to save the comment to the central repository.", + NotifyDescriptor.ERROR_MESSAGE); + DialogDisplayer.getDefault().notify(notifyDescriptor); } } - - return centralRepoCommentDialog.getNewComment(); + } + + /** + * Retrieve the comment that was last saved. If a comment update was + * canceled or an error occurred while attempting to save the comment, the + * comment will be null. + * + * @return The comment. + */ + public String getComment() { + return comment; } } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java index 2a5a98cd7e..26ceed5500 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java @@ -127,9 +127,12 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi try { OtherOccurrenceNodeData selectedNode = (OtherOccurrenceNodeData) tableModel.getRow(otherCasesTable.getSelectedRow()); AddEditCentralRepoCommentAction action = new AddEditCentralRepoCommentAction(selectedNode.createCorrelationAttribute()); - String currentComment = action.addEditCentralRepoComment(); - selectedNode.updateComment(currentComment); - otherCasesTable.repaint(); + action.actionPerformed(null); + String currentComment = action.getComment(); + if (currentComment != null) { + selectedNode.updateComment(action.getComment()); + otherCasesTable.repaint(); + } } catch (EamDbException ex) { logger.log(Level.SEVERE, "Error performing Add/Edit Central Repository Comment action", ex); } From af56427c4421ea9ff8ddbf0cc6b7c1e72b4a914c Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Sat, 7 Jul 2018 00:56:37 -0400 Subject: [PATCH 009/105] Fixed typos; minor code polish. --- .../AddEditCentralRepoCommentAction.java | 8 ++++---- .../centralrepository/CentralRepoCommentDialog.java | 13 +------------ 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java b/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java index 8bca85ac70..af59d2754c 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java @@ -46,7 +46,7 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction { private String comment; /** - * Private constructor to create an instance given a CorrelationAttribute. + * Constructor to create an instance given a CorrelationAttribute. * * @param correlationAttribute The correlation attribute to modify. */ @@ -56,7 +56,7 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction { } /** - * Private constructor to create an instance given an AbstractFile. + * Constructor to create an instance given an AbstractFile. * * @param file The file from which a correlation attribute to modify is * derived. @@ -76,7 +76,7 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction { * exists there, or a new file instance will be added to the database with * the comment attached otherwise. * - * The current comment for this instance is is saved in case it is needed to + * The current comment for this instance is saved in case it is needed to * update the display. If the comment was not changed either due to the * action being canceled or the occurrence of an error, the comment will be * null. @@ -100,7 +100,7 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction { dbManager.updateAttributeInstanceComment(correlationAttribute); } - comment = centralRepoCommentDialog.getNewComment(); + comment = centralRepoCommentDialog.getComment(); } catch (EamDbException ex) { logger.log(Level.SEVERE, "Error adding comment", ex); NotifyDescriptor notifyDescriptor = new NotifyDescriptor.Message( diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.java b/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.java index 88708be173..529ffb8529 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.java @@ -34,7 +34,6 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog { private final CorrelationAttribute correlationAttribute; private boolean commentUpdated = false; private String currentComment = ""; - private String originalComment = ""; /** * Create an instance. @@ -51,7 +50,6 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog { // Store the original comment if (instance.getComment() != null) { currentComment = instance.getComment(); - originalComment = currentComment; } pathLabel.setText(instance.getFilePath()); @@ -88,18 +86,9 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog { * * @return the comment */ - String getNewComment() { + String getComment() { return currentComment; } - - /** - * Get the original comment. - * - * @return the comment - */ - String getOriginalComment() { - return originalComment; - } /** * This method is called from within the constructor to initialize the form. From 6b442c8f36126842b63f04f222bf43c55721f4bf Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Mon, 9 Jul 2018 13:44:14 -0400 Subject: [PATCH 010/105] Disable menu item when correlation attribute not available. --- .../AddEditCentralRepoCommentAction.java | 9 +++++++++ .../CentralRepoContextMenuActionsProvider.java | 12 ++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java b/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java index af59d2754c..df98197428 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java @@ -121,4 +121,13 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction { public String getComment() { return comment; } + + /** + * Retrieve the associated correlation attribute. + * + * @return The correlation attribute. + */ + public CorrelationAttribute getCorrelationAttribute() { + return correlationAttribute; + } } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoContextMenuActionsProvider.java b/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoContextMenuActionsProvider.java index dff9be8f91..65a980558c 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoContextMenuActionsProvider.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoContextMenuActionsProvider.java @@ -38,19 +38,23 @@ public class CentralRepoContextMenuActionsProvider implements ContextMenuActions @Override public List getActions() { - ArrayList actions = new ArrayList<>(); + ArrayList actionsList = new ArrayList<>(); Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); if (selectedFiles.size() != 1) { - return actions; + return actionsList; } for (AbstractFile file : selectedFiles) { if (EamDbUtil.useCentralRepo() && EamArtifactUtil.isSupportedAbstractFileType(file) && file.isFile()) { - actions.add(new AddEditCentralRepoCommentAction(file)); + AddEditCentralRepoCommentAction action = new AddEditCentralRepoCommentAction(file); + if (action.getCorrelationAttribute() == null) { + action.setEnabled(false); + } + actionsList.add(action); } } - return actions; + return actionsList; } } From d7c93a4e8eede6b9150f3fd2252e5085836a6fa2 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Mon, 9 Jul 2018 16:30:29 -0400 Subject: [PATCH 011/105] Removed stack trace for lack of MD5. --- .../datamodel/EamArtifactUtil.java | 41 ++++++++++++++----- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java index 6aad75d38e..808b314af0 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java @@ -235,21 +235,37 @@ public class EamArtifactUtil { return null; } - CorrelationAttribute correlationAttribute = null; - + CorrelationAttribute correlationAttribute; + CorrelationAttribute.Type type; + CorrelationCase correlationCase; + CorrelationDataSource correlationDataSource; + String value; + String filePath; + try { - CorrelationAttribute.Type type = EamDb.getInstance().getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID); - CorrelationCase correlationCase = EamDb.getInstance().getCase(Case.getCurrentCaseThrows()); + type = EamDb.getInstance().getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID); + correlationCase = EamDb.getInstance().getCase(Case.getCurrentCaseThrows()); if (null == correlationCase) { correlationCase = EamDb.getInstance().newCase(Case.getCurrentCaseThrows()); } - CorrelationDataSource correlationDataSource = CorrelationDataSource.fromTSKDataSource(correlationCase, file.getDataSource()); - String value = file.getMd5Hash(); - String filePath = (file.getParentPath() + file.getName()).toLowerCase(); - - correlationAttribute = EamDb.getInstance().getCorrelationAttribute(type, correlationCase, correlationDataSource, value, filePath); - } catch (TskCoreException | EamDbException | NoCurrentCaseException ex) { + correlationDataSource = CorrelationDataSource.fromTSKDataSource(correlationCase, file.getDataSource()); + value = file.getMd5Hash(); + filePath = (file.getParentPath() + file.getName()).toLowerCase(); + } catch (TskCoreException | EamDbException ex) { logger.log(Level.SEVERE, "Error retrieving correlation attribute.", ex); + return null; + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Case is closed.", ex); + return null; + } + + try { + correlationAttribute = EamDb.getInstance().getCorrelationAttribute(type, correlationCase, correlationDataSource, value, filePath); + } catch (EamDbException ex) { + logger.log(Level.WARNING, String.format( + "Correlation attribute could not be retrieved for '%s' (id=%d): %s", + content.getName(), content.getId(), ex.getMessage())); + return null; } return correlationAttribute; @@ -300,9 +316,12 @@ public class EamArtifactUtil { af.getParentPath() + af.getName()); eamArtifact.addInstance(cei); return eamArtifact; - } catch (TskCoreException | EamDbException | NoCurrentCaseException ex) { + } catch (TskCoreException | EamDbException ex) { logger.log(Level.SEVERE, "Error making correlation attribute.", ex); return null; + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Case is closed.", ex); + return null; } } From 75fbb309b9ad390b5ce9261ec5e228d994a01be8 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 11 Jul 2018 01:35:06 -0400 Subject: [PATCH 012/105] Column width adjustments handled. --- .../DataContentViewerOtherCases.form | 24 +--- .../DataContentViewerOtherCases.java | 123 +++++++++-------- ...DataContentViewerOtherCasesTableModel.java | 126 ++++++++++-------- 3 files changed, 142 insertions(+), 131 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.form b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.form index 7b9e47c236..9c42be16a8 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.form +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.form @@ -133,23 +133,18 @@ - - - + - - - - - - - - + + + + + @@ -230,13 +225,6 @@ - - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java index ebc5b7c375..1c69671b05 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.centralrepository.contentviewer; import java.awt.Component; +import java.awt.FontMetrics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedWriter; @@ -86,7 +87,10 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi private static final long serialVersionUID = -1L; - private final static Logger logger = Logger.getLogger(DataContentViewerOtherCases.class.getName()); + private static final Logger logger = Logger.getLogger(DataContentViewerOtherCases.class.getName()); + + private static final int DEFAULT_MIN_CELL_WIDTH = 15; + private static final int CELL_TEXT_WIDTH_PADDING = 5; private final DataContentViewerOtherCasesTableModel tableModel; private final Collection correlationAttributes; @@ -459,12 +463,12 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi @Messages({"DataContentViewerOtherCases.earliestCaseNotAvailable= Not Enabled."}) /** - * Gets the list of Eam Cases and determines the earliest case creation date. - * Sets the label to display the earliest date string to the user. + * Gets the list of Eam Cases and determines the earliest case creation + * date. Sets the label to display the earliest date string to the user. */ - private void setEarliestCaseDate() { - String dateStringDisplay = Bundle.DataContentViewerOtherCases_earliestCaseNotAvailable(); - + private void setEarliestCaseDate() { + String dateStringDisplay = Bundle.DataContentViewerOtherCases_earliestCaseNotAvailable(); + if (EamDb.isEnabled()) { LocalDateTime earliestDate = LocalDateTime.now(DateTimeZone.UTC); DateFormat datetimeFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.US); @@ -472,15 +476,15 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi EamDb dbManager = EamDb.getInstance(); List cases = dbManager.getCases(); for (CorrelationCase aCase : cases) { - LocalDateTime caseDate = LocalDateTime.fromDateFields(datetimeFormat.parse(aCase.getCreationDate())); - - if (caseDate.isBefore(earliestDate)) { + LocalDateTime caseDate = LocalDateTime.fromDateFields(datetimeFormat.parse(aCase.getCreationDate())); + + if (caseDate.isBefore(earliestDate)) { earliestDate = caseDate; dateStringDisplay = aCase.getCreationDate(); - } + } } - + } catch (EamDbException ex) { logger.log(Level.SEVERE, "Error getting list of cases from database.", ex); // NON-NLS } catch (ParseException ex) { @@ -492,10 +496,10 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi } /** - * Query the central repo database (if enabled) and the case database to find all - * artifact instances correlated to the given central repository artifact. If the - * central repo is not enabled, this will only return files from the current case - * with matching MD5 hashes. + * Query the central repo database (if enabled) and the case database to + * find all artifact instances correlated to the given central repository + * artifact. If the central repo is not enabled, this will only return files + * from the current case with matching MD5 hashes. * * @param corAttr CorrelationAttribute to query for * @param dataSourceName Data source to filter results @@ -503,19 +507,19 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi * * @return A collection of correlated artifact instances */ - private Map getCorrelatedInstances(CorrelationAttribute corAttr, String dataSourceName, String deviceId) { + private Map getCorrelatedInstances(CorrelationAttribute corAttr, String dataSourceName, String deviceId) { // @@@ Check exception try { final Case openCase = Case.getCurrentCase(); String caseUUID = openCase.getName(); - HashMap nodeDataMap = new HashMap<>(); + HashMap nodeDataMap = new HashMap<>(); if (EamDb.isEnabled()) { List instances = EamDb.getInstance().getArtifactInstancesByTypeValue(corAttr.getCorrelationType(), corAttr.getCorrelationValue()); - for (CorrelationAttributeInstance artifactInstance:instances) { - + for (CorrelationAttributeInstance artifactInstance : instances) { + // Only add the attribute if it isn't the object the user selected. // We consider it to be a different object if at least one of the following is true: // - the case UUID is different @@ -534,7 +538,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi } } - if (corAttr.getCorrelationType().getDisplayName().equals("Files")) { + if (corAttr.getCorrelationType().getDisplayName().equals("Files")) { List caseDbFiles = getCaseDbMatches(corAttr, openCase); for (AbstractFile caseDbFile : caseDbFiles) { @@ -557,13 +561,17 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi } /** - * Get all other abstract files in the current case with the same MD5 as the selected node. + * Get all other abstract files in the current case with the same MD5 as the + * selected node. + * * @param corAttr The CorrelationAttribute containing the MD5 to search for * @param openCase The current case + * * @return List of matching AbstractFile objects + * * @throws NoCurrentCaseException * @throws TskCoreException - * @throws EamDbException + * @throws EamDbException */ private List getCaseDbMatches(CorrelationAttribute corAttr, Case openCase) throws NoCurrentCaseException, TskCoreException, EamDbException { String md5 = corAttr.getCorrelationValue(); @@ -583,18 +591,18 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi /** * Adds the file to the nodeDataMap map if it does not already exist - * - * @param autopsyCase + * + * @param autopsyCase * @param nodeDataMap * @param newFile * * @throws TskCoreException * @throws EamDbException */ - private void addOrUpdateNodeData(final Case autopsyCase, Map nodeDataMap, AbstractFile newFile) throws TskCoreException, EamDbException { - + private void addOrUpdateNodeData(final Case autopsyCase, Map nodeDataMap, AbstractFile newFile) throws TskCoreException, EamDbException { + OtherOccurrenceNodeInstanceData newNode = new OtherOccurrenceNodeInstanceData(newFile, autopsyCase); - + // If the caseDB object has a notable tag associated with it, update // the known status to BAD if (newNode.getKnown() != TskData.FileKnown.BAD) { @@ -610,7 +618,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi // Make a key to see if the file is already in the map UniquePathKey uniquePathKey = new UniquePathKey(newNode); - + // If this node is already in the list, the only thing we need to do is // update the known status to BAD if the caseDB version had known status BAD. // Otherwise this is a new node so add the new node to the map. @@ -639,7 +647,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi } else { return this.file != null && this.file.getSize() > 0 - && ((this.file.getMd5Hash() != null) && ( ! this.file.getMd5Hash().isEmpty())); + && ((this.file.getMd5Hash() != null) && (!this.file.getMd5Hash().isEmpty())); } } @@ -683,7 +691,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi // get the attributes we can correlate on correlationAttributes.addAll(getCorrelationAttributesFromNode(node)); for (CorrelationAttribute corAttr : correlationAttributes) { - Map correlatedNodeDataMap = new HashMap<>(0); + Map correlatedNodeDataMap = new HashMap<>(0); // get correlation and reference set instances from DB correlatedNodeDataMap.putAll(getCorrelatedInstances(corAttr, dataSourceName, deviceId)); @@ -696,25 +704,40 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi if (correlationAttributes.isEmpty()) { tableModel.addNodeData(new OtherOccurrenceNodeMessageData(Bundle.DataContentViewerOtherCases_table_noArtifacts())); - //DLG: Removing columns causes problems. Look into resizing columns. + setColumnWidthToText(0, Bundle.DataContentViewerOtherCases_table_noArtifacts()); } else if (0 == tableModel.getRowCount()) { tableModel.addNodeData(new OtherOccurrenceNodeMessageData(Bundle.DataContentViewerOtherCases_table_noResultsFound())); - //DLG: Removing columns causes problems. Look into resizing columns. + setColumnWidthToText(0, Bundle.DataContentViewerOtherCases_table_noResultsFound()); } else { setColumnWidths(); } setEarliestCaseDate(); } + /** + * Adjust a given column for the text provided. + * + * @param columnIndex The index of the column to adjust. + * @param text The text whose length will be used to adjust the + * column width. + */ + private void setColumnWidthToText(int columnIndex, String text) { + TableColumn column = otherCasesTable.getColumnModel().getColumn(columnIndex); + FontMetrics fontMetrics = otherCasesTable.getFontMetrics(otherCasesTable.getFont()); + int stringWidth = fontMetrics.stringWidth(text); + column.setMinWidth(stringWidth + CELL_TEXT_WIDTH_PADDING); + } + /** * Adjust column widths to their preferred values. */ private void setColumnWidths() { for (int idx = 0; idx < tableModel.getColumnCount(); idx++) { TableColumn column = otherCasesTable.getColumnModel().getColumn(idx); - int colWidth = tableModel.getColumnPreferredWidth(idx); - if (0 < colWidth) { - column.setPreferredWidth(colWidth); + column.setMinWidth(DEFAULT_MIN_CELL_WIDTH); + int columnWidth = tableModel.getColumnPreferredWidth(idx); + if (columnWidth > 0) { + column.setPreferredWidth(columnWidth); } } } @@ -742,7 +765,6 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi earliestCaseLabel = new javax.swing.JLabel(); earliestCaseDate = new javax.swing.JLabel(); tableStatusPanel = new javax.swing.JPanel(); - tableStatusPanelLabel = new javax.swing.JLabel(); rightClickPopupMenu.addPopupMenuListener(new javax.swing.event.PopupMenuListener() { public void popupMenuCanceled(javax.swing.event.PopupMenuEvent evt) { @@ -804,8 +826,6 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi .addGap(0, 16, Short.MAX_VALUE) ); - tableStatusPanelLabel.setForeground(new java.awt.Color(255, 0, 51)); - javax.swing.GroupLayout tableContainerPanelLayout = new javax.swing.GroupLayout(tableContainerPanel); tableContainerPanel.setLayout(tableContainerPanelLayout); tableContainerPanelLayout.setHorizontalGroup( @@ -818,20 +838,16 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi .addComponent(earliestCaseLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(earliestCaseDate) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(tableStatusPanelLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addContainerGap()) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); tableContainerPanelLayout.setVerticalGroup( tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, tableContainerPanelLayout.createSequentialGroup() - .addComponent(tableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 176, Short.MAX_VALUE) - .addGap(0, 0, 0) - .addGroup(tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(earliestCaseLabel) - .addComponent(earliestCaseDate)) - .addComponent(tableStatusPanelLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(tableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 27, Short.MAX_VALUE) + .addGap(2, 2, 2) + .addGroup(tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(earliestCaseLabel) + .addComponent(earliestCaseDate)) .addGap(0, 0, 0) .addComponent(tableStatusPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(0, 0, 0)) @@ -850,7 +866,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi .addGap(0, 483, Short.MAX_VALUE) .addGroup(otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(otherCasesPanelLayout.createSequentialGroup() - .addComponent(tableContainerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 483, Short.MAX_VALUE) + .addComponent(tableContainerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 59, Short.MAX_VALUE) .addGap(0, 0, 0))) ); @@ -862,7 +878,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(otherCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 483, Short.MAX_VALUE) + .addComponent(otherCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 59, Short.MAX_VALUE) ); }// //GEN-END:initComponents @@ -898,7 +914,6 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi private javax.swing.JPanel tableContainerPanel; private javax.swing.JScrollPane tableScrollPane; private javax.swing.JPanel tableStatusPanel; - private javax.swing.JLabel tableStatusPanelLabel; // End of variables declaration//GEN-END:variables /** @@ -925,9 +940,9 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi @Override public boolean equals(Object other) { if (other instanceof UniquePathKey) { - UniquePathKey otherKey = (UniquePathKey)(other); - return ( Objects.equals(otherKey.dataSourceID, this.dataSourceID) - && Objects.equals(otherKey.filePath, this.filePath) + UniquePathKey otherKey = (UniquePathKey) (other); + return (Objects.equals(otherKey.dataSourceID, this.dataSourceID) + && Objects.equals(otherKey.filePath, this.filePath) && Objects.equals(otherKey.type, this.type)); } return false; diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java index de528e2d42..9ae79259c2 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java @@ -107,71 +107,79 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel { return Bundle.DataContentViewerOtherCasesTableModel_noData(); } - return mapValueById(rowIdx, TableColumns.values()[colIdx]); + OtherOccurrenceNodeData nodeData = nodeDataList.get(rowIdx); + TableColumns columnId = TableColumns.values()[colIdx]; + if (nodeData instanceof OtherOccurrenceNodeMessageData) { + return mapNodeMessageData((OtherOccurrenceNodeMessageData) nodeData, columnId); + } + return mapNodeInstanceData((OtherOccurrenceNodeInstanceData) nodeData, columnId); + } + + /** + * Map a column ID to the value in that cell for node message data. + * + * @param nodeData The node message data. + * @param columnId The ID of the cell column. + * + * @return The value in the cell. + */ + private Object mapNodeMessageData(OtherOccurrenceNodeMessageData nodeData, TableColumns columnId) { + if (columnId == TableColumns.CASE_NAME) { + return nodeData.getDisplayMessage(); + } + return ""; + } + + /** + * Map a column ID to the value in that cell for node instance data. + * + * @param nodeData The node instance data. + * @param columnId The ID of the cell column. + * + * @return The value in the cell. + */ + private Object mapNodeInstanceData(OtherOccurrenceNodeInstanceData nodeData, TableColumns columnId) { + String value = Bundle.DataContentViewerOtherCasesTableModel_noData(); + + switch (columnId) { + case CASE_NAME: + if (null != nodeData.getCaseName()) { + value = nodeData.getCaseName(); + } + break; + case DEVICE: + if (null != nodeData.getDeviceID()) { + value = nodeData.getDeviceID(); + } + break; + case DATA_SOURCE: + if (null != nodeData.getDataSourceName()) { + value = nodeData.getDataSourceName(); + } + break; + case FILE_PATH: + value = nodeData.getFilePath(); + break; + case ATTRIBUTE: + value = nodeData.getType(); + break; + case VALUE: + value = nodeData.getValue(); + break; + case KNOWN: + value = nodeData.getKnown().getName(); + break; + case COMMENT: + value = nodeData.getComment(); + break; + } + return value; } Object getRow(int rowIdx) { return nodeDataList.get(rowIdx); } - /** - * Map a rowIdx and colId to the value in that cell. - * - * @param rowIdx Index of row to search - * @param colId ID of column to search - * - * @return value in the cell - */ - private Object mapValueById(int rowIdx, TableColumns colId) { - OtherOccurrenceNodeData nodeData = nodeDataList.get(rowIdx); - - if (nodeData instanceof OtherOccurrenceNodeMessageData) { - if (colId == TableColumns.CASE_NAME) { - OtherOccurrenceNodeMessageData messageData = (OtherOccurrenceNodeMessageData) nodeData; - return messageData.getDisplayMessage(); - } else { - return ""; - } - } - - OtherOccurrenceNodeInstanceData instanceData = (OtherOccurrenceNodeInstanceData) nodeData; - String value = Bundle.DataContentViewerOtherCasesTableModel_noData(); - - switch (colId) { - case CASE_NAME: - if (null != instanceData.getCaseName()) { - value = instanceData.getCaseName(); - } - break; - case DEVICE: - if (null != instanceData.getDeviceID()) { - value = instanceData.getDeviceID(); - } - break; - case DATA_SOURCE: - if (null != instanceData.getDataSourceName()) { - value = instanceData.getDataSourceName(); - } - break; - case FILE_PATH: - value = instanceData.getFilePath(); - break; - case ATTRIBUTE: - value = instanceData.getType(); - break; - case VALUE: - value = instanceData.getValue(); - break; - case KNOWN: - value = instanceData.getKnown().getName(); - break; - case COMMENT: - value = instanceData.getComment(); - break; - } - return value; - } - @Override public Class getColumnClass(int colIdx) { return String.class; From 718d28e8cc22b7405d022581b4965d2475586b6a Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Mon, 16 Jul 2018 12:02:55 -0400 Subject: [PATCH 013/105] Changed finishing message. --- Core/src/org/sleuthkit/autopsy/imagewriter/ImageWriter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/imagewriter/ImageWriter.java b/Core/src/org/sleuthkit/autopsy/imagewriter/ImageWriter.java index 71404c76e7..4200620749 100644 --- a/Core/src/org/sleuthkit/autopsy/imagewriter/ImageWriter.java +++ b/Core/src/org/sleuthkit/autopsy/imagewriter/ImageWriter.java @@ -134,7 +134,7 @@ class ImageWriter implements PropertyChangeListener{ @Messages({ "# {0} - data source name", - "ImageWriter.progressBar.message=Finishing acquisition of {0}" + "ImageWriter.progressBar.message=Finishing acquisition of {0} (unplug device to cancel)" }) private void startFinishImage(String dataSourceName){ From 263a63fb7e436abffe4ccb876a40846ea44aef4e Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 17 Jul 2018 16:03:32 -0400 Subject: [PATCH 014/105] Added '(Volatility)' to the Memory DSP name. --- .../autopsy/experimental/volatilityDSP/MemoryDSProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/volatilityDSP/MemoryDSProcessor.java b/Experimental/src/org/sleuthkit/autopsy/experimental/volatilityDSP/MemoryDSProcessor.java index dc05cb8376..5dbdca94ce 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/volatilityDSP/MemoryDSProcessor.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/volatilityDSP/MemoryDSProcessor.java @@ -56,7 +56,7 @@ public class MemoryDSProcessor implements DataSourceProcessor { * * @return A data source type display string for this data source processor. */ - @Messages({"MemoryDSProcessor.dataSourceType=Memory Image File"}) + @Messages({"MemoryDSProcessor.dataSourceType=Memory Image File (Volatility)"}) public static String getType() { return Bundle.MemoryDSProcessor_dataSourceType(); } From fbc91771d2aa8fd8e95cf87fd3ce94a54c35b957 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 18 Jul 2018 12:14:57 -0400 Subject: [PATCH 015/105] Set checkbox by default. --- Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java index cb1ec5ddfd..c5c8fb32fb 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java @@ -257,6 +257,7 @@ final class LocalDiskPanel extends JPanel { pathTextField.setEnabled(copyImageCheckbox.isSelected()); browseButton.setEnabled(copyImageCheckbox.isSelected()); changeDatabasePathCheckbox.setEnabled(copyImageCheckbox.isSelected()); + changeDatabasePathCheckbox.setSelected(copyImageCheckbox.isSelected()); fireUpdateEvent(); }//GEN-LAST:event_copyImageCheckboxActionPerformed From 60446f04066a0138d8f5f534e75256c19af33c13 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 18 Jul 2018 13:47:07 -0400 Subject: [PATCH 016/105] Added VHD to picker. --- .../org/sleuthkit/autopsy/casemodule/MissingImageDialog.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java index 5645e1d5d6..78cef08b25 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java @@ -46,11 +46,13 @@ class MissingImageDialog extends javax.swing.JDialog { SleuthkitCase db; static final GeneralFilter rawFilter = new GeneralFilter(GeneralFilter.RAW_IMAGE_EXTS, GeneralFilter.RAW_IMAGE_DESC); static final GeneralFilter encaseFilter = new GeneralFilter(GeneralFilter.ENCASE_IMAGE_EXTS, GeneralFilter.ENCASE_IMAGE_DESC); + static final GeneralFilter virtualMachineFilter = new GeneralFilter(GeneralFilter.VIRTUAL_MACHINE_EXTS, GeneralFilter.VIRTUAL_MACHINE_DESC); static final List allExt = new ArrayList(); static { allExt.addAll(GeneralFilter.RAW_IMAGE_EXTS); allExt.addAll(GeneralFilter.ENCASE_IMAGE_EXTS); + allExt.addAll(GeneralFilter.VIRTUAL_MACHINE_EXTS); } static final String allDesc = NbBundle.getMessage(MissingImageDialog.class, "MissingImageDialog.allDesc.text"); static final GeneralFilter allFilter = new GeneralFilter(allExt, allDesc); @@ -74,6 +76,7 @@ class MissingImageDialog extends javax.swing.JDialog { fc.addChoosableFileFilter(rawFilter); fc.addChoosableFileFilter(encaseFilter); + fc.addChoosableFileFilter(virtualMachineFilter); fc.setFileFilter(allFilter); selectButton.setEnabled(false); From dceb7e884eb47c2fa687404980f94997bef660b3 Mon Sep 17 00:00:00 2001 From: esaunders Date: Wed, 18 Jul 2018 16:01:57 -0400 Subject: [PATCH 017/105] The use of AutoIngestJob as a node key in the dashboard caused problems because (a) the underlying job objects could be changed in other threads and (b) the equals() implementation only considered the manifest file path.New AutoIngestWrapper class was introduced to be used as a key. --- .../autoingest/AinStatusPanel.java | 12 -- .../autoingest/AutoIngestJobsNode.java | 158 ++++++++++++--- .../autoingest/AutoIngestMonitor.java | 183 +++++++++--------- 3 files changed, 219 insertions(+), 134 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AinStatusPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AinStatusPanel.java index 1cc10fab76..d744abe8b4 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AinStatusPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AinStatusPanel.java @@ -125,18 +125,6 @@ final class AinStatusPanel extends javax.swing.JPanel implements ExplorerManager setLayout(new java.awt.BorderLayout()); }// //GEN-END:initComponents - /** - * Get the AutoIngestJob for the currently selected node of this panel. - * - * @return AutoIngestJob which is currently selected in this panel - */ - AutoIngestJob getSelectedAutoIngestJob() { - Node[] selectedRows = explorerManager.getSelectedNodes(); - if (selectedRows.length == 1) { - return ((JobNode) selectedRows[0]).getAutoIngestJob(); - } - return null; - } // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java index 552e44834c..d5bfbd13d8 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java @@ -26,6 +26,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; +import java.util.Objects; import org.openide.nodes.AbstractNode; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; @@ -33,8 +34,10 @@ import org.openide.nodes.Node; import org.openide.nodes.Sheet; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.datamodel.NodeProperty; +import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestJob.Stage; import org.sleuthkit.autopsy.guiutils.DurationCellRenderer; import org.sleuthkit.autopsy.guiutils.StatusIconCellRenderer; +import org.sleuthkit.autopsy.ingest.DataSourceIngestJob; /** * A node which represents all AutoIngestJobs of a given AutoIngestJobStatus. @@ -77,10 +80,103 @@ final class AutoIngestJobsNode extends AbstractNode { refreshChildrenEventBus.post(refreshEvent); } + /** + * The AutoIngestJob class considers auto ingest jobs to be equal if they + * have the same manifest path. This is not sufficient for the purposes of + * determining when the state of a job has changed. This class is used to + * distinguish between different auto ingest jobs based on the manifest + * path, the processing stage, the job snapshot and priority. + */ + private static final class AutoIngestJobWrapper implements Comparable { + + private final AutoIngestJob autoIngestJob; + + /** + * We keep our own references to the following job attributes because + * they can be changed by events in other threads which + */ + private final Stage jobStage; + private final List jobSnapshot; + private final Integer jobPriority; + + AutoIngestJobWrapper(AutoIngestJob job) { + autoIngestJob = job; + jobStage = job.getProcessingStage(); + jobSnapshot = job.getIngestJobSnapshots(); + jobPriority = job.getPriority(); + } + + AutoIngestJob getJob() { + return autoIngestJob; + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof AutoIngestJobWrapper)) { + return false; + } + + if (this == other) { + return true; + } + + AutoIngestJob thisJob = this.autoIngestJob; + AutoIngestJob otherJob = ((AutoIngestJobWrapper) other).autoIngestJob; + + // Only equal if the manifest paths and processing stage details are the same. + return thisJob.getManifest().getFilePath().equals(otherJob.getManifest().getFilePath()) + && jobStage.equals(((AutoIngestJobWrapper) other).jobStage) + && jobSnapshot.equals(((AutoIngestJobWrapper) other).jobSnapshot) + && jobPriority.equals(((AutoIngestJobWrapper) other).jobPriority); + } + + @Override + public int hashCode() { + int hash = 7; + hash = 23 * hash + Objects.hashCode(this.autoIngestJob.getManifest().getFilePath()); + hash = 23 * hash + Objects.hashCode(this.jobStage); + hash = 23 * hash + Objects.hashCode(this.jobSnapshot); + hash = 23 * hash + Objects.hashCode(this.jobPriority); + return hash; + } + + @Override + public int compareTo(AutoIngestJobWrapper o) { + return autoIngestJob.compareTo(o.autoIngestJob); + } + + /** + * The remaining methods simply delegate to the wrapped job. + */ + Manifest getManifest() { + return autoIngestJob.getManifest(); + } + + boolean getErrorsOccurred() { + return autoIngestJob.getErrorsOccurred(); + } + + Date getCompletedDate() { + return autoIngestJob.getCompletedDate(); + } + + AutoIngestJob.StageDetails getProcessingStageDetails() { + return autoIngestJob.getProcessingStageDetails(); + } + + String getProcessingHostName() { + return autoIngestJob.getProcessingHostName(); + } + + Integer getPriority() { + return autoIngestJob.getPriority(); + } + } + /** * A ChildFactory for generating JobNodes. */ - static final class AutoIngestNodeChildren extends ChildFactory { + static final class AutoIngestNodeChildren extends ChildFactory { private final AutoIngestJobStatus autoIngestJobStatus; private AutoIngestMonitor monitor; @@ -104,7 +200,7 @@ final class AutoIngestJobsNode extends AbstractNode { } @Override - protected boolean createKeys(List list) { + protected boolean createKeys(List list) { List jobs; switch (autoIngestJobStatus) { case PENDING_JOB: @@ -121,13 +217,15 @@ final class AutoIngestJobsNode extends AbstractNode { jobs = new ArrayList<>(); } if (jobs != null && jobs.size() > 0) { - list.addAll(jobs); + jobs.forEach(j -> { + list.add(new AutoIngestJobWrapper(j)); + }); } return true; } @Override - protected Node createNodeForKey(AutoIngestJob key) { + protected Node createNodeForKey(AutoIngestJobWrapper key) { return new JobNode(key, autoIngestJobStatus, refreshEventBus); } @@ -179,7 +277,7 @@ final class AutoIngestJobsNode extends AbstractNode { */ static final class JobNode extends AbstractNode { - private final AutoIngestJob autoIngestJob; + private final AutoIngestJobWrapper jobWrapper; private final AutoIngestJobStatus jobStatus; private final RefreshNodeSubscriber refreshNodeSubscriber = new RefreshNodeSubscriber(); @@ -190,12 +288,12 @@ final class AutoIngestJobsNode extends AbstractNode { * @param status - the current status of the AutoIngestJob being * represented */ - JobNode(AutoIngestJob job, AutoIngestJobStatus status, EventBus eventBus) { + JobNode(AutoIngestJobWrapper job, AutoIngestJobStatus status, EventBus eventBus) { super(Children.LEAF); jobStatus = status; - autoIngestJob = job; - setName(autoIngestJob.toString()); //alows job to be uniquely found by name since it will involve a hash of the AutoIngestJob - setDisplayName(autoIngestJob.getManifest().getCaseName()); //displays user friendly case name as name + jobWrapper = job; + setName(jobWrapper.toString()); //alows job to be uniquely found by name since it will involve a hash of the AutoIngestJob + setDisplayName(jobWrapper.getManifest().getCaseName()); //displays user friendly case name as name refreshNodeSubscriber.register(eventBus); } @@ -205,7 +303,7 @@ final class AutoIngestJobsNode extends AbstractNode { * @return autoIngestJob */ AutoIngestJob getAutoIngestJob() { - return autoIngestJob; + return jobWrapper.getJob(); } @Override @@ -220,20 +318,20 @@ final class AutoIngestJobsNode extends AbstractNode { s.put(ss); } ss.put(new NodeProperty<>(Bundle.AutoIngestJobsNode_caseName_text(), Bundle.AutoIngestJobsNode_caseName_text(), Bundle.AutoIngestJobsNode_caseName_text(), - autoIngestJob.getManifest().getCaseName())); + jobWrapper.getManifest().getCaseName())); ss.put(new NodeProperty<>(Bundle.AutoIngestJobsNode_dataSource_text(), Bundle.AutoIngestJobsNode_dataSource_text(), Bundle.AutoIngestJobsNode_dataSource_text(), - autoIngestJob.getManifest().getDataSourcePath().getFileName().toString())); + jobWrapper.getManifest().getDataSourcePath().getFileName().toString())); switch (jobStatus) { case PENDING_JOB: ss.put(new NodeProperty<>(Bundle.AutoIngestJobsNode_jobCreated_text(), Bundle.AutoIngestJobsNode_jobCreated_text(), Bundle.AutoIngestJobsNode_jobCreated_text(), - autoIngestJob.getManifest().getDateFileCreated())); + jobWrapper.getManifest().getDateFileCreated())); ss.put(new NodeProperty<>(Bundle.AutoIngestJobsNode_priority_text(), Bundle.AutoIngestJobsNode_priority_text(), Bundle.AutoIngestJobsNode_priority_text(), - autoIngestJob.getPriority() > 0 ? Bundle.AutoIngestJobsNode_prioritized_true() : Bundle.AutoIngestJobsNode_prioritized_false())); + jobWrapper.getPriority() > 0 ? Bundle.AutoIngestJobsNode_prioritized_true() : Bundle.AutoIngestJobsNode_prioritized_false())); break; case RUNNING_JOB: - AutoIngestJob.StageDetails status = autoIngestJob.getProcessingStageDetails(); + AutoIngestJob.StageDetails status = jobWrapper.getProcessingStageDetails(); ss.put(new NodeProperty<>(Bundle.AutoIngestJobsNode_hostName_text(), Bundle.AutoIngestJobsNode_hostName_text(), Bundle.AutoIngestJobsNode_hostName_text(), - autoIngestJob.getProcessingHostName())); + jobWrapper.getProcessingHostName())); ss.put(new NodeProperty<>(Bundle.AutoIngestJobsNode_stage_text(), Bundle.AutoIngestJobsNode_stage_text(), Bundle.AutoIngestJobsNode_stage_text(), status.getDescription())); ss.put(new NodeProperty<>(Bundle.AutoIngestJobsNode_stageTime_text(), Bundle.AutoIngestJobsNode_stageTime_text(), Bundle.AutoIngestJobsNode_stageTime_text(), @@ -241,11 +339,11 @@ final class AutoIngestJobsNode extends AbstractNode { break; case COMPLETED_JOB: ss.put(new NodeProperty<>(Bundle.AutoIngestJobsNode_jobCreated_text(), Bundle.AutoIngestJobsNode_jobCreated_text(), Bundle.AutoIngestJobsNode_jobCreated_text(), - autoIngestJob.getManifest().getDateFileCreated())); + jobWrapper.getManifest().getDateFileCreated())); ss.put(new NodeProperty<>(Bundle.AutoIngestJobsNode_jobCompleted_text(), Bundle.AutoIngestJobsNode_jobCompleted_text(), Bundle.AutoIngestJobsNode_jobCompleted_text(), - autoIngestJob.getCompletedDate())); + jobWrapper.getCompletedDate())); ss.put(new NodeProperty<>(Bundle.AutoIngestJobsNode_status_text(), Bundle.AutoIngestJobsNode_status_text(), Bundle.AutoIngestJobsNode_status_text(), - autoIngestJob.getErrorsOccurred() ? StatusIconCellRenderer.Status.WARNING : StatusIconCellRenderer.Status.OK)); + jobWrapper.getErrorsOccurred() ? StatusIconCellRenderer.Status.WARNING : StatusIconCellRenderer.Status.OK)); break; default: } @@ -258,24 +356,24 @@ final class AutoIngestJobsNode extends AbstractNode { if (AutoIngestDashboard.isAdminAutoIngestDashboard()) { switch (jobStatus) { case PENDING_JOB: - actions.add(new PrioritizationAction.PrioritizeJobAction(autoIngestJob)); - actions.add(new PrioritizationAction.PrioritizeCaseAction(autoIngestJob)); - PrioritizationAction.DeprioritizeJobAction deprioritizeJobAction = new PrioritizationAction.DeprioritizeJobAction(autoIngestJob); - deprioritizeJobAction.setEnabled(autoIngestJob.getPriority() > 0); + actions.add(new PrioritizationAction.PrioritizeJobAction(jobWrapper.getJob())); + actions.add(new PrioritizationAction.PrioritizeCaseAction(jobWrapper.getJob())); + PrioritizationAction.DeprioritizeJobAction deprioritizeJobAction = new PrioritizationAction.DeprioritizeJobAction(jobWrapper.getJob()); + deprioritizeJobAction.setEnabled(jobWrapper.getPriority() > 0); actions.add(deprioritizeJobAction); - PrioritizationAction.DeprioritizeCaseAction deprioritizeCaseAction = new PrioritizationAction.DeprioritizeCaseAction(autoIngestJob); - deprioritizeCaseAction.setEnabled(autoIngestJob.getPriority() > 0); + PrioritizationAction.DeprioritizeCaseAction deprioritizeCaseAction = new PrioritizationAction.DeprioritizeCaseAction(jobWrapper.getJob()); + deprioritizeCaseAction.setEnabled(jobWrapper.getPriority() > 0); actions.add(deprioritizeCaseAction); break; case RUNNING_JOB: - actions.add(new AutoIngestAdminActions.ProgressDialogAction(autoIngestJob)); - actions.add(new AutoIngestAdminActions.CancelJobAction(autoIngestJob)); + actions.add(new AutoIngestAdminActions.ProgressDialogAction(jobWrapper.getJob())); + actions.add(new AutoIngestAdminActions.CancelJobAction(jobWrapper.getJob())); // actions.add(new AutoIngestAdminActions.CancelModuleAction()); break; case COMPLETED_JOB: - actions.add(new AutoIngestAdminActions.ReprocessJobAction(autoIngestJob)); - actions.add(new AutoIngestAdminActions.DeleteCaseAction(autoIngestJob)); - actions.add(new AutoIngestAdminActions.ShowCaseLogAction(autoIngestJob)); + actions.add(new AutoIngestAdminActions.ReprocessJobAction(jobWrapper.getJob())); + actions.add(new AutoIngestAdminActions.DeleteCaseAction(jobWrapper.getJob())); + actions.add(new AutoIngestAdminActions.ShowCaseLogAction(jobWrapper.getJob())); break; default: } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java index 876a56c47e..b8f596abf7 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java @@ -423,7 +423,7 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen */ new Thread(() -> { eventPublisher.publishRemotely(new AutoIngestCasePrioritizedEvent(LOCAL_HOST_NAME, caseName, - AutoIngestManager.getSystemUserNameProperty(), AutoIngestCasePrioritizedEvent.EventType.CASE_DEPRIORITIZED, "")); + AutoIngestManager.getSystemUserNameProperty(), AutoIngestCasePrioritizedEvent.EventType.CASE_DEPRIORITIZED, "")); }).start(); } } @@ -474,7 +474,7 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen */ new Thread(() -> { eventPublisher.publishRemotely(new AutoIngestCasePrioritizedEvent(LOCAL_HOST_NAME, caseName, - AutoIngestManager.getSystemUserNameProperty(), AutoIngestCasePrioritizedEvent.EventType.CASE_PRIORITIZED, "")); + AutoIngestManager.getSystemUserNameProperty(), AutoIngestCasePrioritizedEvent.EventType.CASE_PRIORITIZED, "")); }).start(); } } @@ -529,7 +529,7 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen final String dataSourceName = jobToDeprioritize.getManifest().getDataSourceFileName(); new Thread(() -> { eventPublisher.publishRemotely(new AutoIngestCasePrioritizedEvent(LOCAL_HOST_NAME, caseName, - AutoIngestManager.getSystemUserNameProperty(), AutoIngestCasePrioritizedEvent.EventType.JOB_DEPRIORITIZED, dataSourceName)); + AutoIngestManager.getSystemUserNameProperty(), AutoIngestCasePrioritizedEvent.EventType.JOB_DEPRIORITIZED, dataSourceName)); }).start(); } @@ -590,7 +590,7 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen final String dataSourceName = jobToPrioritize.getManifest().getDataSourceFileName(); new Thread(() -> { eventPublisher.publishRemotely(new AutoIngestCasePrioritizedEvent(LOCAL_HOST_NAME, caseName, - AutoIngestManager.getSystemUserNameProperty(), AutoIngestCasePrioritizedEvent.EventType.JOB_PRIORITIZED, dataSourceName)); + AutoIngestManager.getSystemUserNameProperty(), AutoIngestCasePrioritizedEvent.EventType.JOB_PRIORITIZED, dataSourceName)); }).start(); } @@ -748,12 +748,11 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen } /** - * A task that updates the state maintained by the monitor. - * At present this includes auto ingest job and auto ingest node data. - * The job data is refreshed by querying the coordination service for - * auto ingest manifest nodes. - * The auto ingest node data is refreshed by publishing a message asking - * all nodes to report their state. + * A task that updates the state maintained by the monitor. At present this + * includes auto ingest job and auto ingest node data. The job data is + * refreshed by querying the coordination service for auto ingest manifest + * nodes. The auto ingest node data is refreshed by publishing a message + * asking all nodes to report their state. */ private final class StateRefreshTask implements Runnable { @@ -861,100 +860,100 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen } - /** - * Class that represents the state of an AIN for the dashboard. - */ - static final class AutoIngestNodeState { - /** - * The set of AIN states. + * Class that represents the state of an AIN for the dashboard. */ - enum State { - STARTING_UP, - SHUTTING_DOWN, - RUNNING, - PAUSE_REQUESTED, - PAUSED_BY_REQUEST, - PAUSED_DUE_TO_SYSTEM_ERROR, - UNKNOWN - } + static final class AutoIngestNodeState { - private final String nodeName; - private final State nodeState; - private final Instant lastSeenTime; - - AutoIngestNodeState(String name, Event event) { - nodeName = name; - switch (event) { - case STARTING_UP: - nodeState = State.STARTING_UP; - break; - case SHUTTING_DOWN: - nodeState = State.SHUTTING_DOWN; - break; - case RUNNING: - nodeState = State.RUNNING; - break; - case PAUSED_BY_USER_REQUEST: - nodeState = State.PAUSED_BY_REQUEST; - break; - case PAUSED_FOR_SYSTEM_ERROR: - nodeState = State.PAUSED_DUE_TO_SYSTEM_ERROR; - break; - case RESUMED: - nodeState = State.RUNNING; - break; - case PAUSE_REQUESTED: - nodeState = State.PAUSE_REQUESTED; - break; - default: - nodeState = State.UNKNOWN; - break; + /** + * The set of AIN states. + */ + enum State { + STARTING_UP, + SHUTTING_DOWN, + RUNNING, + PAUSE_REQUESTED, + PAUSED_BY_REQUEST, + PAUSED_DUE_TO_SYSTEM_ERROR, + UNKNOWN } - lastSeenTime = Instant.now(); - } - String getName() { - return nodeName; - } + private final String nodeName; + private final State nodeState; + private final Instant lastSeenTime; - State getState() { - return nodeState; - } + AutoIngestNodeState(String name, Event event) { + nodeName = name; + switch (event) { + case STARTING_UP: + nodeState = State.STARTING_UP; + break; + case SHUTTING_DOWN: + nodeState = State.SHUTTING_DOWN; + break; + case RUNNING: + nodeState = State.RUNNING; + break; + case PAUSED_BY_USER_REQUEST: + nodeState = State.PAUSED_BY_REQUEST; + break; + case PAUSED_FOR_SYSTEM_ERROR: + nodeState = State.PAUSED_DUE_TO_SYSTEM_ERROR; + break; + case RESUMED: + nodeState = State.RUNNING; + break; + case PAUSE_REQUESTED: + nodeState = State.PAUSE_REQUESTED; + break; + default: + nodeState = State.UNKNOWN; + break; + } + lastSeenTime = Instant.now(); + } - Instant getLastSeenTime() { - return lastSeenTime; - } - } + String getName() { + return nodeName; + } - /** - * Exception type thrown when there is an error completing an auto ingest - * monitor operation. - */ - static final class AutoIngestMonitorException extends Exception { + State getState() { + return nodeState; + } - private static final long serialVersionUID = 1L; - - /** - * Constructs an instance of the exception type thrown when there is an - * error completing an auto ingest monitor operation. - * - * @param message The exception message. - */ - private AutoIngestMonitorException(String message) { - super(message); + Instant getLastSeenTime() { + return lastSeenTime; + } } /** - * Constructs an instance of the exception type thrown when there is an - * error completing an auto ingest monitor operation. - * - * @param message The exception message. - * @param cause A Throwable cause for the error. + * Exception type thrown when there is an error completing an auto + * ingest monitor operation. */ - private AutoIngestMonitorException(String message, Throwable cause) { - super(message, cause); - } + static final class AutoIngestMonitorException extends Exception { + private static final long serialVersionUID = 1L; + + /** + * Constructs an instance of the exception type thrown when there is + * an error completing an auto ingest monitor operation. + * + * @param message The exception message. + */ + private AutoIngestMonitorException(String message) { + super(message); + } + + /** + * Constructs an instance of the exception type thrown when there is + * an error completing an auto ingest monitor operation. + * + * @param message The exception message. + * @param cause A Throwable cause for the error. + */ + private AutoIngestMonitorException(String message, Throwable cause) { + super(message, cause); + } + + } } -} From 5410db46cf7f8ec6f3e25467f7aaa8714dcf6bd8 Mon Sep 17 00:00:00 2001 From: esaunders Date: Wed, 18 Jul 2018 16:09:24 -0400 Subject: [PATCH 018/105] Fix formatting. --- .../autoingest/AutoIngestMonitor.java | 178 +++++++++--------- 1 file changed, 89 insertions(+), 89 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java index b8f596abf7..cfdf6cf973 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java @@ -698,8 +698,8 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen } // Remove jobs associated with this case from the completed jobs collection. - jobsSnapshot.completedJobs.removeIf((AutoIngestJob completedJob) -> - completedJob.getManifest().getCaseName().equals(caseName)); + jobsSnapshot.completedJobs.removeIf((AutoIngestJob completedJob) + -> completedJob.getManifest().getCaseName().equals(caseName)); // Publish a message to update auto ingest nodes. eventPublisher.publishRemotely(new AutoIngestCaseDeletedEvent(caseName, LOCAL_HOST_NAME, AutoIngestManager.getSystemUserNameProperty())); @@ -860,100 +860,100 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen } + /** + * Class that represents the state of an AIN for the dashboard. + */ + static final class AutoIngestNodeState { + /** - * Class that represents the state of an AIN for the dashboard. + * The set of AIN states. */ - static final class AutoIngestNodeState { - - /** - * The set of AIN states. - */ - enum State { - STARTING_UP, - SHUTTING_DOWN, - RUNNING, - PAUSE_REQUESTED, - PAUSED_BY_REQUEST, - PAUSED_DUE_TO_SYSTEM_ERROR, - UNKNOWN - } - - private final String nodeName; - private final State nodeState; - private final Instant lastSeenTime; - - AutoIngestNodeState(String name, Event event) { - nodeName = name; - switch (event) { - case STARTING_UP: - nodeState = State.STARTING_UP; - break; - case SHUTTING_DOWN: - nodeState = State.SHUTTING_DOWN; - break; - case RUNNING: - nodeState = State.RUNNING; - break; - case PAUSED_BY_USER_REQUEST: - nodeState = State.PAUSED_BY_REQUEST; - break; - case PAUSED_FOR_SYSTEM_ERROR: - nodeState = State.PAUSED_DUE_TO_SYSTEM_ERROR; - break; - case RESUMED: - nodeState = State.RUNNING; - break; - case PAUSE_REQUESTED: - nodeState = State.PAUSE_REQUESTED; - break; - default: - nodeState = State.UNKNOWN; - break; - } - lastSeenTime = Instant.now(); - } - - String getName() { - return nodeName; - } - - State getState() { - return nodeState; - } - - Instant getLastSeenTime() { - return lastSeenTime; - } + enum State { + STARTING_UP, + SHUTTING_DOWN, + RUNNING, + PAUSE_REQUESTED, + PAUSED_BY_REQUEST, + PAUSED_DUE_TO_SYSTEM_ERROR, + UNKNOWN } - /** - * Exception type thrown when there is an error completing an auto - * ingest monitor operation. - */ - static final class AutoIngestMonitorException extends Exception { + private final String nodeName; + private final State nodeState; + private final Instant lastSeenTime; - private static final long serialVersionUID = 1L; - - /** - * Constructs an instance of the exception type thrown when there is - * an error completing an auto ingest monitor operation. - * - * @param message The exception message. - */ - private AutoIngestMonitorException(String message) { - super(message); + AutoIngestNodeState(String name, Event event) { + nodeName = name; + switch (event) { + case STARTING_UP: + nodeState = State.STARTING_UP; + break; + case SHUTTING_DOWN: + nodeState = State.SHUTTING_DOWN; + break; + case RUNNING: + nodeState = State.RUNNING; + break; + case PAUSED_BY_USER_REQUEST: + nodeState = State.PAUSED_BY_REQUEST; + break; + case PAUSED_FOR_SYSTEM_ERROR: + nodeState = State.PAUSED_DUE_TO_SYSTEM_ERROR; + break; + case RESUMED: + nodeState = State.RUNNING; + break; + case PAUSE_REQUESTED: + nodeState = State.PAUSE_REQUESTED; + break; + default: + nodeState = State.UNKNOWN; + break; } + lastSeenTime = Instant.now(); + } - /** - * Constructs an instance of the exception type thrown when there is - * an error completing an auto ingest monitor operation. - * - * @param message The exception message. - * @param cause A Throwable cause for the error. - */ - private AutoIngestMonitorException(String message, Throwable cause) { - super(message, cause); - } + String getName() { + return nodeName; + } + State getState() { + return nodeState; + } + + Instant getLastSeenTime() { + return lastSeenTime; } } + + /** + * Exception type thrown when there is an error completing an auto ingest + * monitor operation. + */ + static final class AutoIngestMonitorException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * Constructs an instance of the exception type thrown when there is an + * error completing an auto ingest monitor operation. + * + * @param message The exception message. + */ + private AutoIngestMonitorException(String message) { + super(message); + } + + /** + * Constructs an instance of the exception type thrown when there is an + * error completing an auto ingest monitor operation. + * + * @param message The exception message. + * @param cause A Throwable cause for the error. + */ + private AutoIngestMonitorException(String message, Throwable cause) { + super(message, cause); + } + + } +} From e5a8ae21f557ec6900d2cf4279b0ef21e7e40936 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 18 Jul 2018 16:54:36 -0400 Subject: [PATCH 019/105] Reusing GeneralFilters from Image DSP. --- .../autopsy/casemodule/Bundle.properties | 1 - .../autopsy/casemodule/Bundle_ja.properties | 1 - .../autopsy/casemodule/ImageDSProcessor.java | 18 ++++++++++ .../casemodule/MissingImageDialog.java | 35 +++++++------------ 4 files changed, 31 insertions(+), 24 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index 9c04508c1f..9494b3288a 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -114,7 +114,6 @@ LocalFilesDSProcessor.toString.text=Logical Files LocalFilesPanel.contentType.text=LOCAL LocalFilesPanel.moduleErr=Module Error LocalFilesPanel.moduleErr.msg=A module caused an error listening to LocalFilesPanel updates. See log to determine which module. Some data could be incomplete. -MissingImageDialog.allDesc.text=All Supported Types MissingImageDialog.display.title=Search for Missing Image MissingImageDialog.confDlg.noFileSel.msg=No image file has been selected. Are you sure you\nwould like to exit without finding the image? MissingImageDialog.confDlg.noFileSel.title=Missing Image diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties index 8e405adec4..90849f4639 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties @@ -101,7 +101,6 @@ LocalFilesDSProcessor.toString.text=\u30ed\u30b8\u30ab\u30eb\u30d5\u30a1\u30a4\u LocalFilesPanel.contentType.text=\u30ed\u30fc\u30ab\u30eb LocalFilesPanel.moduleErr=\u30e2\u30b8\u30e5\u30fc\u30eb\u30a8\u30e9\u30fc LocalFilesPanel.moduleErr.msg=LocalFilesPanel\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u3092\u78ba\u8a8d\u4e2d\u306b\u30e2\u30b8\u30e5\u30fc\u30eb\u304c\u30a8\u30e9\u30fc\u3092\u8d77\u3053\u3057\u307e\u3057\u305f\u3002\u3069\u306e\u30e2\u30b8\u30e5\u30fc\u30eb\u304b\u30ed\u30b0\u3092\u78ba\u8a8d\u3057\u3066\u4e0b\u3055\u3044\u3002\u4e00\u90e8\u306e\u30c7\u30fc\u30bf\u304c\u4e0d\u5b8c\u5168\u304b\u3082\u3057\u308c\u307e\u305b\u3093\u3002 -MissingImageDialog.allDesc.text=\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u308b\u5168\u3066\u306e\u30bf\u30a4\u30d7 MissingImageDialog.display.title=\u6b20\u843d\u30a4\u30e1\u30fc\u30b8\u3092\u691c\u7d22 MissingImageDialog.confDlg.noFileSel.msg=\u30a4\u30e1\u30fc\u30b8\u30d5\u30a1\u30a4\u30eb\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002\u30a4\u30e1\u30fc\u30b8\u3092\u898b\u3064\u3051\u308b\n\u524d\u306b\u672c\u5f53\u306b\u7d42\u4e86\u3057\u307e\u3059\u304b\uff1f MissingImageDialog.confDlg.noFileSel.title=\u6b20\u843d\u30a4\u30e1\u30fc\u30b8 diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java index 1e091db81c..fccf740d2e 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java @@ -89,6 +89,24 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour public ImageDSProcessor() { configPanel = ImageFilePanel.createInstance(ImageDSProcessor.class.getName(), filtersList); } + + /** + * Get the list of file extensions supported by this DSP. + * + * @return A list of all supported file extensions. + */ + static List getFileExtensions() { + return allExt; + } + + /** + * Get the list of file filters supported by this DSP. + * + * @return A list of all supported file filters. + */ + static List getFileFiltersList() { + return filtersList; + } /** * Gets a string that describes the type of data sources this processor is diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java index 78cef08b25..894603fe02 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java @@ -28,6 +28,7 @@ import java.io.File; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JOptionPane; +import javax.swing.filechooser.FileFilter; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.coreutils.DriveUtils; @@ -44,19 +45,8 @@ class MissingImageDialog extends javax.swing.JDialog { private static final Logger logger = Logger.getLogger(MissingImageDialog.class.getName()); long obj_id; SleuthkitCase db; - static final GeneralFilter rawFilter = new GeneralFilter(GeneralFilter.RAW_IMAGE_EXTS, GeneralFilter.RAW_IMAGE_DESC); - static final GeneralFilter encaseFilter = new GeneralFilter(GeneralFilter.ENCASE_IMAGE_EXTS, GeneralFilter.ENCASE_IMAGE_DESC); - static final GeneralFilter virtualMachineFilter = new GeneralFilter(GeneralFilter.VIRTUAL_MACHINE_EXTS, GeneralFilter.VIRTUAL_MACHINE_DESC); - static final List allExt = new ArrayList(); - static { - allExt.addAll(GeneralFilter.RAW_IMAGE_EXTS); - allExt.addAll(GeneralFilter.ENCASE_IMAGE_EXTS); - allExt.addAll(GeneralFilter.VIRTUAL_MACHINE_EXTS); - } - static final String allDesc = NbBundle.getMessage(MissingImageDialog.class, "MissingImageDialog.allDesc.text"); - static final GeneralFilter allFilter = new GeneralFilter(allExt, allDesc); - private final JFileChooser fc = new JFileChooser(); + private final JFileChooser fileChooser = new JFileChooser(); /** * Instantiate a MissingImageDialog. @@ -70,14 +60,15 @@ class MissingImageDialog extends javax.swing.JDialog { this.db = db; initComponents(); - fc.setDragEnabled(false); - fc.setFileSelectionMode(JFileChooser.FILES_ONLY); - fc.setMultiSelectionEnabled(false); + fileChooser.setDragEnabled(false); + fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + fileChooser.setMultiSelectionEnabled(false); - fc.addChoosableFileFilter(rawFilter); - fc.addChoosableFileFilter(encaseFilter); - fc.addChoosableFileFilter(virtualMachineFilter); - fc.setFileFilter(allFilter); + List fileFiltersList = ImageDSProcessor.getFileFiltersList(); + for (FileFilter fileFilter : fileFiltersList) { + fileChooser.addChoosableFileFilter(fileFilter); + } + fileChooser.setFileFilter(fileFiltersList.get(0)); selectButton.setEnabled(false); } @@ -289,12 +280,12 @@ class MissingImageDialog extends javax.swing.JDialog { // set the current directory of the FileChooser if the ImagePath Field is valid File currentDir = new File(oldText); if (currentDir.exists()) { - fc.setCurrentDirectory(currentDir); + fileChooser.setCurrentDirectory(currentDir); } - int retval = fc.showOpenDialog(this); + int retval = fileChooser.showOpenDialog(this); if (retval == JFileChooser.APPROVE_OPTION) { - String path = fc.getSelectedFile().getPath(); + String path = fileChooser.getSelectedFile().getPath(); pathNameTextField.setText(path); } //pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.FOCUS_NEXT.toString(), false, true); From b3fafcf06ad9e28901de4cf19decfd9a97f90516 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 18 Jul 2018 16:57:11 -0400 Subject: [PATCH 020/105] Removed unused method. --- .../sleuthkit/autopsy/casemodule/ImageDSProcessor.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java index fccf740d2e..0fb98ea8b8 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java @@ -90,15 +90,6 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour configPanel = ImageFilePanel.createInstance(ImageDSProcessor.class.getName(), filtersList); } - /** - * Get the list of file extensions supported by this DSP. - * - * @return A list of all supported file extensions. - */ - static List getFileExtensions() { - return allExt; - } - /** * Get the list of file filters supported by this DSP. * From a2ad970a7c853741883aed6963cd2fb9d4c79e36 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Thu, 19 Jul 2018 08:47:09 -0400 Subject: [PATCH 021/105] Move call to isOpened onto the EDT --- .../autopsy/directorytree/DirectoryTreeTopComponent.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 95ba2f110c..c84d0ee1f2 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -735,9 +735,11 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat * responsible for opening core windows. Consider moving * this elsewhere. */ - if (!this.isOpened()) { - SwingUtilities.invokeLater(CoreComponentControl::openCoreWindows); - } + SwingUtilities.invokeLater(() -> { + if (! DirectoryTreeTopComponent.this.isOpened()) { + CoreComponentControl.openCoreWindows(); + } + }); } catch (NoCurrentCaseException notUsed) { /** * Case is closed, do nothing. From f1e77aac8991dc67fe2cecf5265fbd4d41f7e71d Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Thu, 19 Jul 2018 09:09:36 -0400 Subject: [PATCH 022/105] set VHD replace option by default. --- Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java index cb1ec5ddfd..c5c8fb32fb 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java @@ -257,6 +257,7 @@ final class LocalDiskPanel extends JPanel { pathTextField.setEnabled(copyImageCheckbox.isSelected()); browseButton.setEnabled(copyImageCheckbox.isSelected()); changeDatabasePathCheckbox.setEnabled(copyImageCheckbox.isSelected()); + changeDatabasePathCheckbox.setSelected(copyImageCheckbox.isSelected()); fireUpdateEvent(); }//GEN-LAST:event_copyImageCheckboxActionPerformed From aba1489aeebc07ba3614022fee23bb7177d1d7b9 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 17 Jul 2018 10:43:33 -0400 Subject: [PATCH 023/105] 4037 Close InputStream in object detection module which was left open --- .../ObjectDetectectionFileIngestModule.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/ObjectDetectectionFileIngestModule.java b/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/ObjectDetectectionFileIngestModule.java index d6bef92ab8..86a35dce23 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/ObjectDetectectionFileIngestModule.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/ObjectDetectectionFileIngestModule.java @@ -101,7 +101,7 @@ public class ObjectDetectectionFileIngestModule extends FileIngestModuleAdapter public ProcessResult process(AbstractFile file) { if (!classifiers.isEmpty() && ImageUtils.isImageThumbnailSupported(file)) { //Any image we can create a thumbnail for is one we should apply the classifiers to - InputStream inputStream = new ReadContentInputStream(file); + InputStream inputStream = new ReadContentInputStream(file); byte[] imageInMemory; try { imageInMemory = IOUtils.toByteArray(inputStream); @@ -109,6 +109,15 @@ public class ObjectDetectectionFileIngestModule extends FileIngestModuleAdapter logger.log(Level.WARNING, "Unable to read image to byte array for performing object detection on " + file.getParentPath() + file.getName() + " with object id of " + file.getId(), ex); return IngestModule.ProcessResult.ERROR; } + finally { + try { + inputStream.close(); + } catch (IOException ex) { + logger.log(Level.SEVERE, "Unable to close input stream after attempting to create byte array for " + file.getParentPath() + file.getName() + " with object id of " + file.getId(), ex); + return IngestModule.ProcessResult.ERROR; + } + } + Mat originalImage; try { originalImage = Highgui.imdecode(new MatOfByte(imageInMemory), Highgui.IMREAD_GRAYSCALE); From 04068dd4928a47974fd1407105dc629c2fdd6350 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 17 Jul 2018 11:10:04 -0400 Subject: [PATCH 024/105] 4037 entirely remove unnecessary input stream in Object Detection --- .../ObjectDetectectionFileIngestModule.java | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/ObjectDetectectionFileIngestModule.java b/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/ObjectDetectectionFileIngestModule.java index 86a35dce23..0e9155617c 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/ObjectDetectectionFileIngestModule.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/ObjectDetectectionFileIngestModule.java @@ -33,6 +33,7 @@ import org.opencv.core.MatOfByte; import org.opencv.core.MatOfRect; import org.opencv.highgui.Highgui; import org.opencv.objdetect.CascadeClassifier; +import org.openide.util.Exceptions; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; @@ -100,23 +101,15 @@ public class ObjectDetectectionFileIngestModule extends FileIngestModuleAdapter @Override public ProcessResult process(AbstractFile file) { if (!classifiers.isEmpty() && ImageUtils.isImageThumbnailSupported(file)) { - //Any image we can create a thumbnail for is one we should apply the classifiers to - InputStream inputStream = new ReadContentInputStream(file); - byte[] imageInMemory; + //Any image we can create a thumbnail for is one we should apply the classifiers to + byte[] imageInMemory = new byte[(int)file.getSize()]; + try { - imageInMemory = IOUtils.toByteArray(inputStream); - } catch (IOException ex) { + file.read(imageInMemory, 0, file.getSize()); + } catch (TskCoreException ex) { logger.log(Level.WARNING, "Unable to read image to byte array for performing object detection on " + file.getParentPath() + file.getName() + " with object id of " + file.getId(), ex); return IngestModule.ProcessResult.ERROR; } - finally { - try { - inputStream.close(); - } catch (IOException ex) { - logger.log(Level.SEVERE, "Unable to close input stream after attempting to create byte array for " + file.getParentPath() + file.getName() + " with object id of " + file.getId(), ex); - return IngestModule.ProcessResult.ERROR; - } - } Mat originalImage; try { From 8d546a217e6011be251baf9122409a24e2cb059e Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 17 Jul 2018 11:14:45 -0400 Subject: [PATCH 025/105] remove unnecessary imports from Object detection --- .../objectdetection/ObjectDetectectionFileIngestModule.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/ObjectDetectectionFileIngestModule.java b/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/ObjectDetectectionFileIngestModule.java index 0e9155617c..398bed8010 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/ObjectDetectectionFileIngestModule.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/ObjectDetectectionFileIngestModule.java @@ -19,21 +19,17 @@ package org.sleuthkit.autopsy.experimental.objectdetection; import java.io.File; -import java.io.IOException; -import java.io.InputStream; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; import org.apache.commons.io.FilenameUtils; -import org.apache.commons.io.IOUtils; import org.opencv.core.CvException; import org.opencv.core.Mat; import org.opencv.core.MatOfByte; import org.opencv.core.MatOfRect; import org.opencv.highgui.Highgui; import org.opencv.objdetect.CascadeClassifier; -import org.openide.util.Exceptions; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; @@ -53,7 +49,6 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED; import org.sleuthkit.datamodel.BlackboardAttribute; -import org.sleuthkit.datamodel.ReadContentInputStream; import org.sleuthkit.datamodel.TskCoreException; /** From fad0f574063312f3895e0bfcad2277267b4fc148 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 17 Jul 2018 11:27:53 -0400 Subject: [PATCH 026/105] 4037 introduce max file size to object detection module (100 mb) --- .../ObjectDetectectionFileIngestModule.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/ObjectDetectectionFileIngestModule.java b/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/ObjectDetectectionFileIngestModule.java index 398bed8010..a6bf2a2ee6 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/ObjectDetectectionFileIngestModule.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/ObjectDetectectionFileIngestModule.java @@ -57,6 +57,7 @@ import org.sleuthkit.datamodel.TskCoreException; public class ObjectDetectectionFileIngestModule extends FileIngestModuleAdapter { private final static Logger logger = Logger.getLogger(ObjectDetectectionFileIngestModule.class.getName()); + private final static int MAX_FILE_SIZE = 100000000; //Max size of pictures to perform object detection on private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter(); private long jobId; private Map classifiers; @@ -97,6 +98,14 @@ public class ObjectDetectectionFileIngestModule extends FileIngestModuleAdapter public ProcessResult process(AbstractFile file) { if (!classifiers.isEmpty() && ImageUtils.isImageThumbnailSupported(file)) { //Any image we can create a thumbnail for is one we should apply the classifiers to + + if (file.getSize() > MAX_FILE_SIZE){ + //prevent it from allocating gigabytes of memory for extremely large files + logger.log(Level.INFO, "Encountered file "+ file.getParentPath() + file.getName() + " with object id of " + + file.getId() + " which exceeds max file size of " + MAX_FILE_SIZE + " bytes, with a size of " + file.getSize()); + return IngestModule.ProcessResult.OK; + } + byte[] imageInMemory = new byte[(int)file.getSize()]; try { From fb28c62d6059d8d13f314ac803291ae985d837fc Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 18 Jul 2018 11:54:16 -0400 Subject: [PATCH 027/105] 4037 add explicit calls to release opencv objects to avoid reliance on finalize method --- .../ObjectDetectectionFileIngestModule.java | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/ObjectDetectectionFileIngestModule.java b/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/ObjectDetectectionFileIngestModule.java index a6bf2a2ee6..003a35a46d 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/ObjectDetectectionFileIngestModule.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/ObjectDetectectionFileIngestModule.java @@ -98,15 +98,15 @@ public class ObjectDetectectionFileIngestModule extends FileIngestModuleAdapter public ProcessResult process(AbstractFile file) { if (!classifiers.isEmpty() && ImageUtils.isImageThumbnailSupported(file)) { //Any image we can create a thumbnail for is one we should apply the classifiers to - - if (file.getSize() > MAX_FILE_SIZE){ - //prevent it from allocating gigabytes of memory for extremely large files - logger.log(Level.INFO, "Encountered file "+ file.getParentPath() + file.getName() + " with object id of " + - file.getId() + " which exceeds max file size of " + MAX_FILE_SIZE + " bytes, with a size of " + file.getSize()); + + if (file.getSize() > MAX_FILE_SIZE) { + //prevent it from allocating gigabytes of memory for extremely large files + logger.log(Level.INFO, "Encountered file " + file.getParentPath() + file.getName() + " with object id of " + + file.getId() + " which exceeds max file size of " + MAX_FILE_SIZE + " bytes, with a size of " + file.getSize()); return IngestModule.ProcessResult.OK; } - - byte[] imageInMemory = new byte[(int)file.getSize()]; + + byte[] imageInMemory = new byte[(int) file.getSize()]; try { file.read(imageInMemory, 0, file.getSize()); @@ -114,7 +114,7 @@ public class ObjectDetectectionFileIngestModule extends FileIngestModuleAdapter logger.log(Level.WARNING, "Unable to read image to byte array for performing object detection on " + file.getParentPath() + file.getName() + " with object id of " + file.getId(), ex); return IngestModule.ProcessResult.ERROR; } - + Mat originalImage; try { originalImage = Highgui.imdecode(new MatOfByte(imageInMemory), Highgui.IMREAD_GRAYSCALE); @@ -127,7 +127,6 @@ public class ObjectDetectectionFileIngestModule extends FileIngestModuleAdapter logger.log(Level.SEVERE, "Unexpected Exception encountered attempting to use OpenCV to decode picture: " + file.getParentPath() + file.getName() + " with object id of " + file.getId(), unexpectedException); return IngestModule.ProcessResult.ERROR; } - MatOfRect detectionRectangles = new MatOfRect(); //the rectangles which reprent the coordinates on the image for where objects were detected for (String classifierKey : classifiers.keySet()) { //apply each classifier to the file @@ -136,9 +135,9 @@ public class ObjectDetectectionFileIngestModule extends FileIngestModuleAdapter } catch (CvException ignored) { //The image was likely an image which we are unable to generate a thumbnail for, and the classifier was likely one where that is not acceptable continue; - } catch (Exception unexpectedException) { + } catch (Exception unexpectedException) { //hopefully an unnecessary generic exception catch but currently present to catch any exceptions OpenCv throws which may not be documented - logger.log(Level.SEVERE, "Unexpected Exception encountered for image " + file.getParentPath() + file.getName() + " with object id of " + file.getId() +" while trying to apply classifier " + classifierKey, unexpectedException); + logger.log(Level.SEVERE, "Unexpected Exception encountered for image " + file.getParentPath() + file.getName() + " with object id of " + file.getId() + " while trying to apply classifier " + classifierKey, unexpectedException); continue; } @@ -169,10 +168,14 @@ public class ObjectDetectectionFileIngestModule extends FileIngestModuleAdapter } catch (TskCoreException ex) { logger.log(Level.SEVERE, String.format("Failed to create blackboard artifact for '%s'.", file.getParentPath() + file.getName()), ex); //NON-NLS + detectionRectangles.release(); + originalImage.release(); return IngestModule.ProcessResult.ERROR; } } } + detectionRectangles.release(); + originalImage.release(); } return IngestModule.ProcessResult.OK; From e970e8b71c76305efc1294619eac353d10547798 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Thu, 19 Jul 2018 10:59:30 -0400 Subject: [PATCH 028/105] Make sure setupTable is called from the EDT --- .../autopsy/corecomponents/DataResultViewerTable.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java index 6ccf1a3c46..7f9049e414 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java @@ -141,7 +141,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer { * Configure the child OutlineView (explorer view) component. */ outlineView.setAllowedDragActions(DnDConstants.ACTION_NONE); - + outline = outlineView.getOutline(); outline.setRowSelectionAllowed(true); outline.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); @@ -252,6 +252,10 @@ public class DataResultViewerTable extends AbstractDataResultViewer { * persisted column order, sorting and visibility is used. */ private void setupTable() { + if (! SwingUtilities.isEventDispatchThread()) { + LOGGER.log(Level.SEVERE, "Attempting to run setupTable() from non-EDT thread"); + return; + } /* * Since we are modifying the columns, we don't want to listen to * added/removed events as un-hide/hide, until the table setup is done. @@ -281,7 +285,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer { * let the table resize itself. */ outline.setAutoResizeMode((props.isEmpty()) ? JTable.AUTO_RESIZE_ALL_COLUMNS : JTable.AUTO_RESIZE_OFF); - + assignColumns(props); // assign columns to match the properties if (firstProp != null) { ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(firstProp.getDisplayName()); From 771f8489a8b940dedeffd1a798dc4730644d6047 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Thu, 19 Jul 2018 11:03:41 -0400 Subject: [PATCH 029/105] Moved EDT check up to setNode() --- .../autopsy/corecomponents/DataResultViewerTable.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java index 7f9049e414..80d42614c1 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java @@ -208,6 +208,11 @@ public class DataResultViewerTable extends AbstractDataResultViewer { @Override @ThreadConfined(type = ThreadConfined.ThreadType.AWT) public void setNode(Node rootNode) { + if (! SwingUtilities.isEventDispatchThread()) { + LOGGER.log(Level.SEVERE, "Attempting to run setNode() from non-EDT thread"); + return; + } + /* * The quick filter must be reset because when determining column width, * ETable.getRowCount is called, and the documentation states that quick @@ -252,10 +257,6 @@ public class DataResultViewerTable extends AbstractDataResultViewer { * persisted column order, sorting and visibility is used. */ private void setupTable() { - if (! SwingUtilities.isEventDispatchThread()) { - LOGGER.log(Level.SEVERE, "Attempting to run setupTable() from non-EDT thread"); - return; - } /* * Since we are modifying the columns, we don't want to listen to * added/removed events as un-hide/hide, until the table setup is done. From 5ab3050362d68c64e8b3f8757d8ba6d39f89b26e Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Thu, 19 Jul 2018 11:15:33 -0400 Subject: [PATCH 030/105] Fixed bugs around checkboxes. --- .../autopsy/report/ReportVisualPanel2.form | 3 ++ .../autopsy/report/ReportVisualPanel2.java | 50 ++++++++++++++----- 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.form b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.form index e1f23ebffc..a67060d6f3 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.form +++ b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.form @@ -97,6 +97,9 @@ + + + diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java index 82de40aac9..03f3bda809 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java @@ -109,7 +109,7 @@ final class ReportVisualPanel2 extends JPanel { } for (TagName tagName : tagNamesInUse) { - String notableString = tagName.getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; + String notableString = tagName.getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; tagStates.put(tagName.getDisplayName() + notableString, Boolean.FALSE); } tags.addAll(tagStates.keySet()); @@ -124,7 +124,9 @@ final class ReportVisualPanel2 extends JPanel { tagsList.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent evt) { - + if (!taggedResultsRadioButton.isSelected()) { + return; + } int index = tagsList.locationToIndex(evt.getPoint()); if (index < tagsModel.getSize() && index >= 0) { String value = tagsModel.getElementAt(index); @@ -184,16 +186,26 @@ final class ReportVisualPanel2 extends JPanel { return tagStates; } + /** + * Are any tags selected? + * + * @return True if any tags are selected; otherwise false. + */ private boolean areTagsSelected() { boolean result = false; for (Entry entry : tagStates.entrySet()) { if (entry.getValue()) { result = true; + break; } } return result; } + /** + * Set the Finish button as either enabled or disabled depending on the UI + * component selections. + */ private void updateFinishButton() { if (taggedResultsRadioButton.isSelected()) { wizPanel.setFinish(areTagsSelected()); @@ -209,6 +221,19 @@ final class ReportVisualPanel2 extends JPanel { return taggedResultsRadioButton.isSelected(); } + /** + * Set all tagged results as either selected or unselected. + * + * @param selected Should all tagged results be selected? + */ + void setAllTaggedResultsSelected(boolean selected) { + for (String tag : tags) { + tagStates.put(tag, (selected ? Boolean.TRUE : Boolean.FALSE)); + } + tagsList.repaint(); + wizPanel.setFinish(selected); + } + /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -234,6 +259,11 @@ final class ReportVisualPanel2 extends JPanel { optionsButtonGroup.add(allResultsRadioButton); org.openide.awt.Mnemonics.setLocalizedText(allResultsRadioButton, org.openide.util.NbBundle.getMessage(ReportVisualPanel2.class, "ReportVisualPanel2.allResultsRadioButton.text")); // NOI18N + allResultsRadioButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + allResultsRadioButtonActionPerformed(evt); + } + }); org.openide.awt.Mnemonics.setLocalizedText(dataLabel, org.openide.util.NbBundle.getMessage(ReportVisualPanel2.class, "ReportVisualPanel2.dataLabel.text")); // NOI18N @@ -312,25 +342,21 @@ final class ReportVisualPanel2 extends JPanel { }// //GEN-END:initComponents private void selectAllButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectAllButtonActionPerformed - for (String tag : tags) { - tagStates.put(tag, Boolean.TRUE); - } - tagsList.repaint(); - wizPanel.setFinish(true); + setAllTaggedResultsSelected(true); }//GEN-LAST:event_selectAllButtonActionPerformed private void deselectAllButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deselectAllButtonActionPerformed - for (String tag : tags) { - tagStates.put(tag, Boolean.FALSE); - } - tagsList.repaint(); - wizPanel.setFinish(false); + setAllTaggedResultsSelected(false); }//GEN-LAST:event_deselectAllButtonActionPerformed private void advancedButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_advancedButtonActionPerformed artifactStates = dialog.display(); }//GEN-LAST:event_advancedButtonActionPerformed + private void allResultsRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_allResultsRadioButtonActionPerformed + setAllTaggedResultsSelected(false); + }//GEN-LAST:event_allResultsRadioButtonActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton advancedButton; private javax.swing.JRadioButton allResultsRadioButton; From e98e0db15b9139a50171a52a5fca4bc964a3edb4 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Thu, 19 Jul 2018 13:41:31 -0400 Subject: [PATCH 031/105] Revert to old method of calling setupTabs --- .../corecomponents/DataResultPanel.java | 34 +++++-------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java index ced154edf7..9d0a83c2ad 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java @@ -26,7 +26,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import javax.swing.JTabbedPane; -import javax.swing.SwingWorker; +import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.openide.explorer.ExplorerManager; @@ -579,29 +579,6 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C } } - /** - * Worker for RootNodeListener childrenAdded. - */ - class SetupTabsChildrenWorker extends SwingWorker { - - private final Node childNode; - - SetupTabsChildrenWorker(Node aChildNode) { - childNode = aChildNode; - } - - @Override - protected Void doInBackground() throws Exception { - setupTabs(childNode); - return null; - } - - @Override - protected void done() { - setupTabs(childNode); - } - } - /** * Responds to changes in the root node due to asynchronous child node * creation. @@ -628,8 +605,13 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C */ if (waitingForData && containsReal(delta)) { waitingForData = false; - Node childNode = nme.getNode(); - new SetupTabsChildrenWorker(childNode).execute(); + if (SwingUtilities.isEventDispatchThread()) { + setupTabs(nme.getNode()); + } else { + SwingUtilities.invokeLater(() -> { + setupTabs(nme.getNode()); + }); + } } } From 8764aeba87ee48f2ba9948c76ebc2126fcf98b5d Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Thu, 19 Jul 2018 14:02:04 -0400 Subject: [PATCH 032/105] Update TSKVersion.xml --- TSKVersion.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TSKVersion.xml b/TSKVersion.xml index 57096d8d35..7350f25b66 100644 --- a/TSKVersion.xml +++ b/TSKVersion.xml @@ -1,3 +1,3 @@ - + From 3bbb3261c970af4db16c59ebc8c6da76cbf021a6 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 19 Jul 2018 17:12:37 -0400 Subject: [PATCH 033/105] 4040 Associate the user name of who created a tag with that tag --- .../casemodule/SingleUserCaseConverter.java | 8 +++++--- .../datamodel/BlackboardArtifactTagNode.java | 11 +++++++++-- .../autopsy/datamodel/ContentTagNode.java | 16 +++++++++++----- .../autopsy/report/TableReportGenerator.java | 13 +++++++++---- 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java b/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java index 46727fc570..95dfad8c5d 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java @@ -859,13 +859,14 @@ public class SingleUserCaseConverter { if (value > biggestPK) { biggestPK = value; } - outputStatement.executeUpdate("INSERT INTO content_tags (tag_id, obj_id, tag_name_id, comment, begin_byte_offset, end_byte_offset) VALUES (" //NON-NLS + outputStatement.executeUpdate("INSERT INTO content_tags (tag_id, obj_id, tag_name_id, comment, begin_byte_offset, end_byte_offset, user_name) VALUES (" //NON-NLS + value + "," + inputResultSet.getLong(2) + "," + inputResultSet.getLong(3) + ",'" + inputResultSet.getString(4) + "'," + inputResultSet.getLong(5) + "," - + inputResultSet.getLong(6) + ")"); //NON-NLS + + inputResultSet.getLong(6) + ",'" + + inputResultSet.getString(7)+ "')"); //NON-NLS } catch (SQLException ex) { if (ex.getErrorCode() != 0) { // 0 if the entry already exists @@ -892,7 +893,8 @@ public class SingleUserCaseConverter { + value + "," + inputResultSet.getLong(2) + "," + inputResultSet.getLong(3) + ",'" - + inputResultSet.getString(4) + "')"); //NON-NLS + + inputResultSet.getString(4) + "','" + + inputResultSet.getString(5) + "')"); //NON-NLS } catch (SQLException ex) { if (ex.getErrorCode() != 0) { // 0 if the entry already exists diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java index ea944b6b43..16cf40680c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java @@ -27,6 +27,7 @@ import javax.swing.Action; import org.openide.nodes.Children; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; @@ -59,6 +60,7 @@ public class BlackboardArtifactTagNode extends DisplayableItemNode { this.tag = tag; } + @Messages({"BlackboardArtifactTagNode.createSheet.userName.text=User Name"}) @Override protected Sheet createSheet() { Sheet propertySheet = super.createSheet(); @@ -80,6 +82,7 @@ public class BlackboardArtifactTagNode extends DisplayableItemNode { Logger.getLogger(ContentTagNode.class.getName()).log(Level.SEVERE, "Failed to get path for content (id = " + tag.getContent().getId() + ")", ex); //NON-NLS contentPath = NbBundle.getMessage(this.getClass(), "BlackboardArtifactTagNode.createSheet.unavail.text"); } + properties.put(new NodeProperty<>( NbBundle.getMessage(this.getClass(), "BlackboardArtifactTagNode.createSheet.srcFilePath.text"), NbBundle.getMessage(this.getClass(), "BlackboardArtifactTagNode.createSheet.srcFilePath.text"), @@ -95,7 +98,11 @@ public class BlackboardArtifactTagNode extends DisplayableItemNode { NbBundle.getMessage(this.getClass(), "BlackboardArtifactTagNode.createSheet.comment.text"), "", tag.getComment())); - + properties.put(new NodeProperty<>( + NbBundle.getMessage(this.getClass(), "BlackboardArtifactTagNode.createSheet.userName.text"), + NbBundle.getMessage(this.getClass(), "BlackboardArtifactTagNode.createSheet.userName.text"), + "", + tag.getUserName())); return propertySheet; } @@ -132,7 +139,7 @@ public class BlackboardArtifactTagNode extends DisplayableItemNode { } actions.add(new ViewTaggedArtifactAction(BlackboardArtifactTagNode_viewSourceArtifact_text(), artifact)); actions.addAll(DataModelActionsFactory.getActions(tag, true)); - + return actions.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java index 547303878b..e213e460cb 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java @@ -59,8 +59,8 @@ class ContentTagNode extends DisplayableItemNode { @Messages({ "ContentTagNode.createSheet.artifactMD5.displayName=MD5 Hash", - "ContentTagNode.createSheet.artifactMD5.name=MD5 Hash" - }) + "ContentTagNode.createSheet.artifactMD5.name=MD5 Hash", + "ContentTagNode.createSheet.userName.text=User Name"}) @Override protected Sheet createSheet() { Content content = tag.getContent(); @@ -115,6 +115,11 @@ class ContentTagNode extends DisplayableItemNode { Bundle.ContentTagNode_createSheet_artifactMD5_displayName(), "", file != null ? StringUtils.defaultString(file.getMd5Hash()) : "")); + properties.put(new NodeProperty<>( + NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.userName.text"), + NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.userName.text"), + "", + tag.getUserName())); return propertySheet; } @@ -123,13 +128,14 @@ class ContentTagNode extends DisplayableItemNode { List actions = new ArrayList<>(); actions.addAll(Arrays.asList(super.getActions(context))); - AbstractFile file = getLookup().lookup(AbstractFile.class); + AbstractFile file = getLookup().lookup(AbstractFile.class + ); if (file != null) { actions.add(ViewFileInTimelineAction.createViewFileAction(file)); } - + actions.addAll(DataModelActionsFactory.getActions(tag, false)); - + return actions.toArray(new Action[actions.size()]); } diff --git a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java index f87851fe87..ff1479cd86 100644 --- a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java @@ -38,6 +38,7 @@ import java.util.Set; import java.util.TreeSet; 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.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.TagsManager; @@ -264,6 +265,7 @@ class TableReportGenerator { /** * Make table for tagged files */ + @Messages({"ReportGenerator.tagTable.header.userName=User Name"}) @SuppressWarnings("deprecation") private void makeContentTagsTables() { @@ -286,7 +288,8 @@ class TableReportGenerator { 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.comment"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.userName"), NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeModified"), NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeChanged"), NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeAccessed"), @@ -324,7 +327,7 @@ class TableReportGenerator { fileName = tag.getContent().getName(); } - ArrayList rowData = new ArrayList<>(Arrays.asList(tag.getName().getDisplayName() + notableString, fileName, tag.getComment())); + ArrayList rowData = new ArrayList<>(Arrays.asList(tag.getName().getDisplayName() + notableString, fileName, tag.getComment(), tag.getUserName())); Content content = tag.getContent(); if (content instanceof AbstractFile) { AbstractFile file = (AbstractFile) content; @@ -386,7 +389,8 @@ class TableReportGenerator { 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")))); + NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.srcFile"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.userName")))); // Give the modules the rows for the content tags. for (BlackboardArtifactTag tag : tags) { @@ -396,7 +400,8 @@ class TableReportGenerator { } List row; - row = new ArrayList<>(Arrays.asList(tag.getArtifact().getArtifactTypeName(), tag.getName().getDisplayName() + notableString, tag.getComment(), tag.getContent().getName())); + row = new ArrayList<>(Arrays.asList(tag.getArtifact().getArtifactTypeName(), tag.getName().getDisplayName() + notableString, + tag.getComment(), tag.getContent().getName(), tag.getUserName())); tableReport.addRow(row); // check if the tag is an image that we should later make a thumbnail for From d70802cb629b851fee1fc16ed7b6866644d56e37 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Fri, 20 Jul 2018 14:55:59 +0200 Subject: [PATCH 034/105] add tooltip to timeline listview description column --- .../sleuthkit/autopsy/timeline/ui/listvew/ListTimeline.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListTimeline.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListTimeline.java index 7515891356..6bc26f8d7a 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListTimeline.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListTimeline.java @@ -567,8 +567,11 @@ class ListTimeline extends BorderPane { super.updateItem(item, empty); if (empty || item == null) { setText(null); + setTooltip(null); } else { - setText(textSupplier.apply(getEvent())); + String text = textSupplier.apply(getEvent()); + setText(text); + setTooltip(new Tooltip(text)); } } } From ffd45d3bf5d96f49d19766b05522f86087146544 Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Fri, 20 Jul 2018 10:27:42 -0400 Subject: [PATCH 035/105] update version --- Core/nbproject/project.properties | 3 +-- Core/nbproject/project.xml | 4 ++-- unix_setup.sh | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Core/nbproject/project.properties b/Core/nbproject/project.properties index b596512161..9ff74aca14 100644 --- a/Core/nbproject/project.properties +++ b/Core/nbproject/project.properties @@ -17,7 +17,6 @@ file.reference.sevenzipjbinding-AllPlatforms.jar=release/modules/ext/sevenzipjbi file.reference.sevenzipjbinding.jar=release/modules/ext/sevenzipjbinding.jar file.reference.sqlite-jdbc-3.8.11.jar=release/modules/ext/sqlite-jdbc-3.8.11.jar file.reference.StixLib.jar=release/modules/ext/StixLib.jar -file.reference.sleuthkit-postgresql-4.6.1.jar=release/modules/ext/sleuthkit-postgresql-4.6.1.jar file.reference.bcprov-jdk15on-1.54.jar=release/modules/ext/bcprov-jdk15on-1.54.jar file.reference.jackcess-2.1.8.jar=release/modules/ext/jackcess-2.1.8.jar file.reference.jackcess-encrypt-2.1.2.jar=release/modules/ext/jackcess-encrypt-2.1.2.jar @@ -30,7 +29,7 @@ file.reference.cxf-rt-transports-http-3.0.16.jar=release/modules/ext/cxf-rt-tran file.reference.fontbox-2.0.8.jar=release/modules/ext/fontbox-2.0.8.jar file.reference.pdfbox-2.0.8.jar=release/modules/ext/pdfbox-2.0.8.jar file.reference.pdfbox-tools-2.0.8.jar=release/modules/ext/pdfbox-tools-2.0.8.jar -file.reference.sleuthkit-postgresql-4.6.1.jar=release/modules/ext/sleuthkit-postgresql-4.6.1.jar +file.reference.sleuthkit-postgresql-4.6.2.jar=release/modules/ext/sleuthkit-postgresql-4.6.2.jar file.reference.tika-core-1.17.jar=release/modules/ext/tika-core-1.17.jar file.reference.tika-parsers-1.17.jar=release/modules/ext/tika-parsers-1.17.jar file.reference.curator-client-2.8.0.jar=release/modules/ext/curator-client-2.8.0.jar diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index 57cbc58c25..46ad7c5426 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -412,8 +412,8 @@ release/modules/ext/metadata-extractor-2.10.1.jar - ext/sleuthkit-postgresql-4.6.1.jar - release/modules/ext/sleuthkit-postgresql-4.6.1.jar + ext/sleuthkit-postgresql-4.6.2.jar + release/modules/ext/sleuthkit-postgresql-4.6.2.jar ext/tika-core-1.17.jar diff --git a/unix_setup.sh b/unix_setup.sh index 970c35a5c2..1cf9b65888 100755 --- a/unix_setup.sh +++ b/unix_setup.sh @@ -2,7 +2,7 @@ # Verifies programs are installed and copies native code into the Autopsy folder structure -TSK_VERSION=4.6.1 +TSK_VERSION=4.6.2 # Verify PhotoRec was installed photorec_filepath=/usr/bin/photorec From f283009c6831f24f30eda08ba7c4429687e9def0 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 20 Jul 2018 15:02:12 -0400 Subject: [PATCH 036/105] Changed form layout to conform with Add Keywords. --- .../AddHashValuesToDatabaseDialog.form | 48 +++++++++---------- .../AddHashValuesToDatabaseDialog.java | 45 +++++++++-------- .../modules/hashdatabase/Bundle.properties | 2 +- .../modules/hashdatabase/Bundle_ja.properties | 2 +- 4 files changed, 47 insertions(+), 50 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.form b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.form index da0b07d99d..bf4e6ef5a8 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.form +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.form @@ -26,20 +26,21 @@ - + - + + - - - - - - - + + + + + + + @@ -47,21 +48,18 @@ - - + + - - - - - - - - - - + + + + + + + - + @@ -102,14 +100,14 @@ - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.java index 68535928c7..bcae027d61 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.java @@ -73,7 +73,7 @@ public class AddHashValuesToDatabaseDialog extends javax.swing.JDialog { } else { setDefaultCloseOperation(0); } - AddValuesToHashDatabaseButton.setEnabled(enable); + okButton.setEnabled(enable); cancelButton.setEnabled(enable); pasteFromClipboardButton.setEnabled(enable); } @@ -91,7 +91,7 @@ public class AddHashValuesToDatabaseDialog extends javax.swing.JDialog { jScrollPane1 = new javax.swing.JScrollPane(); hashValuesTextArea = new javax.swing.JTextArea(); pasteFromClipboardButton = new javax.swing.JButton(); - AddValuesToHashDatabaseButton = new javax.swing.JButton(); + okButton = new javax.swing.JButton(); cancelButton = new javax.swing.JButton(); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); @@ -115,10 +115,10 @@ public class AddHashValuesToDatabaseDialog extends javax.swing.JDialog { } }); - org.openide.awt.Mnemonics.setLocalizedText(AddValuesToHashDatabaseButton, org.openide.util.NbBundle.getMessage(AddHashValuesToDatabaseDialog.class, "AddHashValuesToDatabaseDialog.AddValuesToHashDatabaseButton.text_2")); // NOI18N - AddValuesToHashDatabaseButton.addActionListener(new java.awt.event.ActionListener() { + org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(AddHashValuesToDatabaseDialog.class, "AddHashValuesToDatabaseDialog.okButton.text_2")); // NOI18N + okButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - AddValuesToHashDatabaseButtonActionPerformed(evt); + okButtonActionPerformed(evt); } }); @@ -136,31 +136,30 @@ public class AddHashValuesToDatabaseDialog extends javax.swing.JDialog { .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jScrollPane1) .addGroup(layout.createSequentialGroup() .addComponent(instructionLabel) .addGap(0, 0, Short.MAX_VALUE)) - .addComponent(jScrollPane1)) - .addGap(18, 18, 18) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(AddValuesToHashDatabaseButton, javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(cancelButton, javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(pasteFromClipboardButton, javax.swing.GroupLayout.Alignment.TRAILING)) + .addGroup(layout.createSequentialGroup() + .addComponent(pasteFromClipboardButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 121, Short.MAX_VALUE) + .addComponent(okButton, javax.swing.GroupLayout.PREFERRED_SIZE, 84, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cancelButton, javax.swing.GroupLayout.PREFERRED_SIZE, 84, javax.swing.GroupLayout.PREFERRED_SIZE))) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addContainerGap() .addComponent(instructionLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(AddValuesToHashDatabaseButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(cancelButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(pasteFromClipboardButton)) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 274, Short.MAX_VALUE)) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 279, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(pasteFromClipboardButton) + .addComponent(okButton) + .addComponent(cancelButton)) .addContainerGap()) ); @@ -213,17 +212,17 @@ public class AddHashValuesToDatabaseDialog extends javax.swing.JDialog { } }//GEN-LAST:event_hashValuesTextAreaMouseClicked - private void AddValuesToHashDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_AddValuesToHashDatabaseButtonActionPerformed + private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed AddHashValuesToDatabaseProgressDialog progressDialog = new AddHashValuesToDatabaseProgressDialog(this, hashDb, hashValuesTextArea.getText()); progressDialog.addHashValuesToDatabase(); - }//GEN-LAST:event_AddValuesToHashDatabaseButtonActionPerformed + }//GEN-LAST:event_okButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JButton AddValuesToHashDatabaseButton; private javax.swing.JButton cancelButton; private javax.swing.JTextArea hashValuesTextArea; private javax.swing.JLabel instructionLabel; private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JButton okButton; private javax.swing.JButton pasteFromClipboardButton; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties index c5f6d82425..cbf25e548c 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties @@ -172,7 +172,6 @@ HashDbSearchPanel.hashTable.defaultModel.title.text=MD5 Hashes AddHashValuesToDatabaseDialog.JDialog.Title=Add Hashes to Hash Set AddHashValuesToDatabaseDialog.instructionLabel.text_1=Paste MD5 hash values (one per line) below: AddHashValuesToDatabaseDialog.cancelButton.text_2=Cancel -AddHashValuesToDatabaseDialog.AddValuesToHashDatabaseButton.text_2=Add Hashes to Hash Set AddHashValuesToDatabaseDialog.pasteFromClipboardButton.text_2=Paste From Clipboard AddHashValuesToDatabaseProgressDialog.okButton.text=OK AddHashValuesToDatabaseProgressDialog.statusLabel.text=status @@ -237,3 +236,4 @@ HashDbCreateDatabaseDialog.centralRepoRadioButton.text=Remote (Central Repositor HashDbCreateDatabaseDialog.lbOrg.text=Source Organization: HashDbCreateDatabaseDialog.orgButton.text=Manage Organizations HashDbCreateDatabaseDialog.databasePathLabel.text=Hash Set Path: +AddHashValuesToDatabaseDialog.okButton.text_2=OK diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties index 828b027bdb..431529542f 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties @@ -172,7 +172,6 @@ AddHashValuesToDatabaseDialog.JDialog.Title=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9 HashLookupSettingsPanel.addHashesToDatabaseButton.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306b\u30cf\u30c3\u30b7\u30e5\u3092\u8ffd\u52a0 AddHashValuesToDatabaseDialog.instructionLabel.text_1=\u4e0b\u8a18\u306bMD5\u306e\u30cf\u30c3\u30b7\u30e5\u5024\u3092\u8cbc\u308a\u4ed8\u3051\u308b\uff08\u30e9\u30a4\u30f3\u3054\u3068\u306b\u4e00\u3064\u305a\u3064\uff09\uff1a AddHashValuesToDatabaseDialog.cancelButton.text_2=\u30ad\u30e3\u30f3\u30bb\u30eb -AddHashValuesToDatabaseDialog.AddValuesToHashDatabaseButton.text_2=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306b\u30cf\u30c3\u30b7\u30e5\u3092\u8ffd\u52a0 AddHashValuesToDatabaseDialog.pasteFromClipboardButton.text_2=\u30af\u30ea\u30c3\u30d7\u30dc\u30fc\u30c9\u304b\u3089\u8cbc\u308a\u4ed8\u3051\u308b AddHashValuesToDatabaseProgressDialog.okButton.text=OK AddHashValuesToDatabaseProgressDialog.statusLabel.text=\u30b9\u30c6\u30fc\u30bf\u30b9 @@ -207,3 +206,4 @@ HashLookupSettingsPanel.nameLabel.text=\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c HashLookupSettingsPanel.hashDatabasesLabel.text=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\uff1a HashLookupSettingsPanel.importDatabaseButton.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u30a4\u30f3\u30dd\u30fc\u30c8 HashDbCreateDatabaseDialog.databasePathLabel.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d1\u30b9\uff1a +AddHashValuesToDatabaseDialog.okButton.text_2=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306b\u30cf\u30c3\u30b7\u30e5\u3092\u8ffd\u52a0 From 22768a6ed5c793ad0184955f4f19f234dc22d0c4 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Tue, 24 Jul 2018 15:34:37 -0400 Subject: [PATCH 037/105] First cut at prototyping the solution --- .../AdHocSearchChildFactory.java | 12 +++++--- .../keywordsearch/AdHocSearchDelegator.java | 4 +-- .../keywordsearch/AdHocSearchPanel.java | 4 +-- .../DropdownListSearchPanel.java | 2 +- .../DropdownSingleTermSearchPanel.java | 2 +- .../keywordsearch/IngestSearchRunner.java | 2 +- .../autopsy/keywordsearch/QueryResults.java | 29 ++++++++++--------- 7 files changed, 31 insertions(+), 24 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/AdHocSearchChildFactory.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/AdHocSearchChildFactory.java index accc19cb9a..2e58fa01e6 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/AdHocSearchChildFactory.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/AdHocSearchChildFactory.java @@ -83,9 +83,11 @@ class AdHocSearchChildFactory extends ChildFactory { .collect(Collectors.toList()); private final Collection queryRequests; + private final boolean saveResults; - AdHocSearchChildFactory(Collection queryRequests) { + AdHocSearchChildFactory(Collection queryRequests, boolean saveResults) { this.queryRequests = queryRequests; + this.saveResults = saveResults; } /** @@ -223,7 +225,7 @@ class AdHocSearchChildFactory extends ChildFactory { //cannot reuse snippet in BlackboardResultWriter //because for regex searches in UI we compress results by showing a content per regex once (even if multiple term hits) //whereas in bb we write every hit per content separately - new BlackboardResultWriter(queryResults, queryRequest.getKeywordList().getName()).execute(); + new BlackboardResultWriter(queryResults, queryRequest.getKeywordList().getName(), saveResults).execute(); return true; } @@ -396,10 +398,12 @@ class AdHocSearchChildFactory extends ChildFactory { private final KeywordSearchQuery query; private final QueryResults hits; private static final int QUERY_DISPLAY_LEN = 40; + private final boolean saveResults; - BlackboardResultWriter(QueryResults hits, String listName) { + BlackboardResultWriter(QueryResults hits, String listName, boolean saveResults) { this.hits = hits; this.query = hits.getQuery(); + this.saveResults = saveResults; } protected void finalizeWorker() { @@ -414,7 +418,7 @@ class AdHocSearchChildFactory extends ChildFactory { final String queryDisp = queryStr.length() > QUERY_DISPLAY_LEN ? queryStr.substring(0, QUERY_DISPLAY_LEN - 1) + " ..." : queryStr; try { progress = ProgressHandle.createHandle(NbBundle.getMessage(this.getClass(), "KeywordSearchResultFactory.progress.saving", queryDisp), () -> BlackboardResultWriter.this.cancel(true)); - hits.process(progress, null, this, false); + hits.process(progress, null, this, false, saveResults); } finally { finalizeWorker(); } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/AdHocSearchDelegator.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/AdHocSearchDelegator.java index c085af7a30..4b9a229785 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/AdHocSearchDelegator.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/AdHocSearchDelegator.java @@ -75,7 +75,7 @@ class AdHocSearchDelegator { * Execute the keyword search based on keywords passed into constructor. * Post results into a new DataResultViewer. */ - public void execute() { + public void execute(boolean saveResults) { Collection queryRequests = new ArrayList<>(); int queryID = 0; StringBuilder queryConcat = new StringBuilder(); // concatenation of all query strings @@ -95,7 +95,7 @@ class AdHocSearchDelegator { Node rootNode; if (queryRequests.size() > 0) { Children childNodes = - Children.create(new AdHocSearchChildFactory(queryRequests), true); + Children.create(new AdHocSearchChildFactory(queryRequests, saveResults), true); rootNode = new AbstractNode(childNodes); } else { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/AdHocSearchPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/AdHocSearchPanel.java index a8dbfb6268..ec75de032e 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/AdHocSearchPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/AdHocSearchPanel.java @@ -99,7 +99,7 @@ abstract class AdHocSearchPanel extends javax.swing.JPanel { * Performs the search using the selected keywords. Creates a * DataResultTopComponent with the results. */ - public void search() { + public void search(boolean saveResults) { boolean isIngestRunning = IngestManager.getInstance().isIngestRunning(); if (filesIndexed == 0) { @@ -138,7 +138,7 @@ abstract class AdHocSearchPanel extends javax.swing.JPanel { AdHocSearchDelegator man = new AdHocSearchDelegator(keywordLists, getDataSourcesSelected()); if (man.validate()) { - man.execute(); + man.execute(saveResults); } else { KeywordSearchUtil.displayDialog(keywordSearchErrorDialogHeader, NbBundle.getMessage(this.getClass(), "AbstractKeywordSearchPerformer.search.invalidSyntaxHeader"), KeywordSearchUtil.DIALOG_MESSAGE_TYPE.ERROR); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownListSearchPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownListSearchPanel.java index 0c7566f52e..81611c130a 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownListSearchPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownListSearchPanel.java @@ -333,7 +333,7 @@ class DropdownListSearchPanel extends AdHocSearchPanel { setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); try { - search(); + search(true); // ELTOD do we always want o save these? } finally { setCursor(null); } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.java index bdc80084c7..2ed59d253e 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.java @@ -340,7 +340,7 @@ public class DropdownSingleTermSearchPanel extends AdHocSearchPanel { */ private void keywordTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_keywordTextFieldActionPerformed try { - search(); + search(false); // ELTODO get the checkbox value } catch (Exception e) { LOGGER.log(Level.SEVERE, "Error performing ad hoc single keyword search", e); //NON-NLS } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/IngestSearchRunner.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/IngestSearchRunner.java index 70fd3ba370..cea9fd1a82 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/IngestSearchRunner.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/IngestSearchRunner.java @@ -563,7 +563,7 @@ final class IngestSearchRunner { subProgresses[keywordsSearched].progress(keywordList.getName() + ": " + queryDisplayStr, unitProgress); // Create blackboard artifacts - newResults.process(null, subProgresses[keywordsSearched], this, keywordList.getIngestMessages()); + newResults.process(null, subProgresses[keywordsSearched], this, keywordList.getIngestMessages(), true); } //if has results diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryResults.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryResults.java index e27a01b063..5f672f5f03 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryResults.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryResults.java @@ -143,7 +143,7 @@ class QueryResults { * exrtacted from the text source object. * */ - void process(ProgressHandle progress, ProgressContributor subProgress, SwingWorker worker, boolean notifyInbox) { + void process(ProgressHandle progress, ProgressContributor subProgress, SwingWorker worker, boolean notifyInbox, boolean saveResults) { /* * Initialize the progress indicator to the number of keywords that will * be processed. @@ -218,22 +218,25 @@ class QueryResults { } catch (TskCoreException | NoCurrentCaseException tskCoreException) { logger.log(Level.SEVERE, "Failed to get text source object for ", tskCoreException); //NON-NLS } + + if (saveResults) { - /* + /* * Post an artifact for the hit to the blackboard. - */ - BlackboardArtifact artifact = query.postKeywordHitToBlackboard(content, keyword, hit, snippet, query.getKeywordList().getName()); + */ + BlackboardArtifact artifact = query.postKeywordHitToBlackboard(content, keyword, hit, snippet, query.getKeywordList().getName()); - /* + /* * Send an ingest inbox message for the hit. - */ - if (null != artifact) { - hitArtifacts.add(artifact); - if (notifyInbox) { - try { - writeSingleFileInboxMessage(artifact, content); - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error sending message to ingest messages inbox", ex); //NON-NLS + */ + if (null != artifact) { + hitArtifacts.add(artifact); + if (notifyInbox) { + try { + writeSingleFileInboxMessage(artifact, content); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Error sending message to ingest messages inbox", ex); //NON-NLS + } } } } From c76242a14aa0c7f0ff6e913f0bdf193361c46ec1 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Wed, 25 Jul 2018 10:43:51 -0400 Subject: [PATCH 038/105] First cut at UI --- .../autopsy/keywordsearch/Bundle.properties | 2 ++ .../DropdownSingleTermSearchPanel.form | 25 ++++++++++++++----- .../DropdownSingleTermSearchPanel.java | 22 ++++++++++------ 3 files changed, 36 insertions(+), 13 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties index ee49ae2c2b..81544546da 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties @@ -313,3 +313,5 @@ ExtractedContentPanel.pagesLabel.text=Page: DropdownSingleTermSearchPanel.dataSourceCheckBox.text=Restrict search to the selected data sources: DropdownListSearchPanel.dataSourceCheckBox.text=Restrict search to the selected data sources: DropdownSingleTermSearchPanel.ingestIndexLabel.text=Files Indexed: +DropdownSingleTermSearchPanel.jSaveSearchResults.toolTipText=Performe keyword search without saving the results in the form of keyword hit artifacts +DropdownSingleTermSearchPanel.jSaveSearchResults.text=Save search results diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.form b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.form index 19fb132f0d..b7b26a882a 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.form +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.form @@ -59,14 +59,14 @@ - + + - @@ -74,8 +74,9 @@ + - + @@ -83,14 +84,16 @@ - + - + + + @@ -99,7 +102,7 @@ - + @@ -217,5 +220,15 @@ + + + + + + + + + + diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.java index 2ed59d253e..42bebd6169 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.java @@ -221,6 +221,7 @@ public class DropdownSingleTermSearchPanel extends AdHocSearchPanel { jScrollPane1 = new javax.swing.JScrollPane(); dataSourceList = new javax.swing.JList<>(); ingestIndexLabel = new javax.swing.JLabel(); + jSaveSearchResults = new javax.swing.JCheckBox(); org.openide.awt.Mnemonics.setLocalizedText(cutMenuItem, org.openide.util.NbBundle.getMessage(DropdownSingleTermSearchPanel.class, "DropdownSearchPanel.cutMenuItem.text")); // NOI18N rightClickMenu.add(cutMenuItem); @@ -280,6 +281,9 @@ public class DropdownSingleTermSearchPanel extends AdHocSearchPanel { ingestIndexLabel.setFont(ingestIndexLabel.getFont().deriveFont(ingestIndexLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 10)); org.openide.awt.Mnemonics.setLocalizedText(ingestIndexLabel, org.openide.util.NbBundle.getMessage(DropdownSingleTermSearchPanel.class, "DropdownSingleTermSearchPanel.ingestIndexLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jSaveSearchResults, org.openide.util.NbBundle.getMessage(DropdownSingleTermSearchPanel.class, "DropdownSingleTermSearchPanel.jSaveSearchResults.text")); // NOI18N + jSaveSearchResults.setToolTipText(org.openide.util.NbBundle.getMessage(DropdownSingleTermSearchPanel.class, "DropdownSingleTermSearchPanel.jSaveSearchResults.toolTipText")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -287,32 +291,35 @@ public class DropdownSingleTermSearchPanel extends AdHocSearchPanel { .addGroup(layout.createSequentialGroup() .addGap(5, 5, 5) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jSaveSearchResults) .addGroup(layout.createSequentialGroup() .addComponent(exactRadioButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(substringRadioButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(regexRadioButton)) - .addComponent(dataSourceCheckBox) .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 297, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(layout.createSequentialGroup() .addComponent(searchButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(ingestIndexLabel)) - .addComponent(keywordTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 296, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(keywordTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 296, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(dataSourceCheckBox)) + .addContainerGap(39, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() - .addComponent(keywordTextField, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(keywordTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(exactRadioButton) .addComponent(substringRadioButton) .addComponent(regexRadioButton)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jSaveSearchResults) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(dataSourceCheckBox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 61, javax.swing.GroupLayout.PREFERRED_SIZE) @@ -320,7 +327,7 @@ public class DropdownSingleTermSearchPanel extends AdHocSearchPanel { .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(searchButton) .addComponent(ingestIndexLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 13, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addContainerGap()) + .addGap(29, 29, 29)) ); }// //GEN-END:initComponents @@ -340,7 +347,7 @@ public class DropdownSingleTermSearchPanel extends AdHocSearchPanel { */ private void keywordTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_keywordTextFieldActionPerformed try { - search(false); // ELTODO get the checkbox value + search(jSaveSearchResults.isSelected()); // ELTODO get the checkbox value } catch (Exception e) { LOGGER.log(Level.SEVERE, "Error performing ad hoc single keyword search", e); //NON-NLS } @@ -431,6 +438,7 @@ public class DropdownSingleTermSearchPanel extends AdHocSearchPanel { private javax.swing.JList dataSourceList; private javax.swing.JRadioButton exactRadioButton; private javax.swing.JLabel ingestIndexLabel; + private javax.swing.JCheckBox jSaveSearchResults; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JTextField keywordTextField; private javax.swing.JMenuItem pasteMenuItem; From 43cce4fec253df28ae6e98c6d63afcaa74890723 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Wed, 25 Jul 2018 13:52:58 -0400 Subject: [PATCH 039/105] Added save search feature to list search --- .../autopsy/keywordsearch/Bundle.properties | 2 ++ .../DropdownListSearchPanel.form | 19 +++++++++++++++++-- .../DropdownListSearchPanel.java | 17 +++++++++++++---- .../DropdownSingleTermSearchPanel.java | 2 +- 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties index 81544546da..144609972d 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties @@ -315,3 +315,5 @@ DropdownListSearchPanel.dataSourceCheckBox.text=Restrict search to the selected DropdownSingleTermSearchPanel.ingestIndexLabel.text=Files Indexed: DropdownSingleTermSearchPanel.jSaveSearchResults.toolTipText=Performe keyword search without saving the results in the form of keyword hit artifacts DropdownSingleTermSearchPanel.jSaveSearchResults.text=Save search results +DropdownListSearchPanel.jSaveSearchResults.toolTipText=Performe keyword search without saving the results in the form of keyword hit artifacts +DropdownListSearchPanel.jSaveSearchResults.text=Save search results diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownListSearchPanel.form b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownListSearchPanel.form index 873824840b..c4988ac8a7 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownListSearchPanel.form +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownListSearchPanel.form @@ -33,11 +33,14 @@ + - + + + + - @@ -45,6 +48,8 @@ + + @@ -226,5 +231,15 @@ + + + + + + + + + + diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownListSearchPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownListSearchPanel.java index 81611c130a..8d370fee3b 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownListSearchPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownListSearchPanel.java @@ -206,6 +206,7 @@ class DropdownListSearchPanel extends AdHocSearchPanel { dataSourceCheckBox = new javax.swing.JCheckBox(); jScrollPane1 = new javax.swing.JScrollPane(); dataSourceList = new javax.swing.JList<>(); + jSaveSearchResults = new javax.swing.JCheckBox(); setFont(getFont().deriveFont(getFont().getStyle() & ~java.awt.Font.BOLD, 11)); @@ -265,6 +266,9 @@ class DropdownListSearchPanel extends AdHocSearchPanel { dataSourceList.setMinimumSize(new java.awt.Dimension(0, 200)); jScrollPane1.setViewportView(dataSourceList); + jSaveSearchResults.setText(org.openide.util.NbBundle.getMessage(DropdownListSearchPanel.class, "DropdownListSearchPanel.jSaveSearchResults.text")); // NOI18N + jSaveSearchResults.setToolTipText(org.openide.util.NbBundle.getMessage(DropdownListSearchPanel.class, "DropdownListSearchPanel.jSaveSearchResults.toolTipText")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -278,10 +282,12 @@ class DropdownListSearchPanel extends AdHocSearchPanel { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(ingestIndexLabel) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addGroup(layout.createSequentialGroup() - .addComponent(dataSourceCheckBox) - .addGap(0, 0, Short.MAX_VALUE)) .addComponent(jScrollPane1) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(dataSourceCheckBox) + .addComponent(jSaveSearchResults)) + .addGap(0, 0, Short.MAX_VALUE)) ); layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {manageListsButton, searchAddButton}); @@ -291,6 +297,8 @@ class DropdownListSearchPanel extends AdHocSearchPanel { .addGroup(layout.createSequentialGroup() .addComponent(jSplitPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 183, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jSaveSearchResults) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(dataSourceCheckBox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 65, javax.swing.GroupLayout.PREFERRED_SIZE) @@ -319,6 +327,7 @@ class DropdownListSearchPanel extends AdHocSearchPanel { private javax.swing.JCheckBox dataSourceCheckBox; private javax.swing.JList dataSourceList; private javax.swing.JLabel ingestIndexLabel; + private javax.swing.JCheckBox jSaveSearchResults; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JSplitPane jSplitPane1; private javax.swing.JTable keywordsTable; @@ -333,7 +342,7 @@ class DropdownListSearchPanel extends AdHocSearchPanel { setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); try { - search(true); // ELTOD do we always want o save these? + search(jSaveSearchResults.isSelected()); } finally { setCursor(null); } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.java index 42bebd6169..2407b3b8c4 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.java @@ -347,7 +347,7 @@ public class DropdownSingleTermSearchPanel extends AdHocSearchPanel { */ private void keywordTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_keywordTextFieldActionPerformed try { - search(jSaveSearchResults.isSelected()); // ELTODO get the checkbox value + search(jSaveSearchResults.isSelected()); } catch (Exception e) { LOGGER.log(Level.SEVERE, "Error performing ad hoc single keyword search", e); //NON-NLS } From c3109afc82510efaa4be7f94bc4ce16b2e9dbfca Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Wed, 25 Jul 2018 15:24:38 -0400 Subject: [PATCH 040/105] Moved 'save results' button --- .../DropdownListSearchPanel.form | 28 +++++++++---------- .../DropdownListSearchPanel.java | 28 +++++++++---------- .../DropdownSingleTermSearchPanel.form | 10 +++---- .../DropdownSingleTermSearchPanel.java | 10 +++---- 4 files changed, 36 insertions(+), 40 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownListSearchPanel.form b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownListSearchPanel.form index c4988ac8a7..70cd940085 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownListSearchPanel.form +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownListSearchPanel.form @@ -23,23 +23,21 @@ - - - - - - - - - - + + + + + + + + - + @@ -47,19 +45,19 @@ - - - + + + - + diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownListSearchPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownListSearchPanel.java index 8d370fee3b..12a0ae9b4f 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownListSearchPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownListSearchPanel.java @@ -273,21 +273,19 @@ class DropdownListSearchPanel extends AdHocSearchPanel { this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE) - .addGroup(layout.createSequentialGroup() - .addGap(4, 4, 4) - .addComponent(searchAddButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(manageListsButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(ingestIndexLabel) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(jSplitPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) .addComponent(jScrollPane1) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(dataSourceCheckBox) - .addComponent(jSaveSearchResults)) - .addGap(0, 0, Short.MAX_VALUE)) + .addComponent(jSaveSearchResults) + .addGroup(layout.createSequentialGroup() + .addComponent(searchAddButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(manageListsButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(ingestIndexLabel))) + .addGap(0, 120, Short.MAX_VALUE)) ); layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {manageListsButton, searchAddButton}); @@ -296,18 +294,18 @@ class DropdownListSearchPanel extends AdHocSearchPanel { layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(jSplitPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 183, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jSaveSearchResults) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(dataSourceCheckBox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 65, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jSaveSearchResults) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(manageListsButton) .addComponent(searchAddButton) .addComponent(ingestIndexLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 13, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addContainerGap()) + .addGap(23, 23, 23)) ); }// //GEN-END:initComponents diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.form b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.form index b7b26a882a..81630d6fa5 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.form +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.form @@ -59,7 +59,6 @@ - @@ -68,9 +67,10 @@ + - + @@ -92,17 +92,17 @@ - - + + - + diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.java index 2407b3b8c4..3e33e73a5c 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.java @@ -291,7 +291,6 @@ public class DropdownSingleTermSearchPanel extends AdHocSearchPanel { .addGroup(layout.createSequentialGroup() .addGap(5, 5, 5) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jSaveSearchResults) .addGroup(layout.createSequentialGroup() .addComponent(exactRadioButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) @@ -299,9 +298,10 @@ public class DropdownSingleTermSearchPanel extends AdHocSearchPanel { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(regexRadioButton)) .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 297, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jSaveSearchResults) .addGroup(layout.createSequentialGroup() .addComponent(searchButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGap(18, 18, 18) .addComponent(ingestIndexLabel)) .addComponent(keywordTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 296, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(dataSourceCheckBox)) @@ -318,16 +318,16 @@ public class DropdownSingleTermSearchPanel extends AdHocSearchPanel { .addComponent(substringRadioButton) .addComponent(regexRadioButton)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jSaveSearchResults) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(dataSourceCheckBox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 61, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jSaveSearchResults) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(searchButton) .addComponent(ingestIndexLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 13, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(29, 29, 29)) + .addContainerGap(22, Short.MAX_VALUE)) ); }// //GEN-END:initComponents From 0d516470218de999e7d1fe2ae185b707e10814c7 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Wed, 25 Jul 2018 15:33:43 -0400 Subject: [PATCH 041/105] Updated javadoc --- .../autopsy/keywordsearch/AdHocSearchChildFactory.java | 6 ++++++ .../autopsy/keywordsearch/AdHocSearchDelegator.java | 2 ++ .../sleuthkit/autopsy/keywordsearch/AdHocSearchPanel.java | 2 ++ .../org/sleuthkit/autopsy/keywordsearch/QueryResults.java | 6 +++--- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/AdHocSearchChildFactory.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/AdHocSearchChildFactory.java index 2e58fa01e6..2b279bfa88 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/AdHocSearchChildFactory.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/AdHocSearchChildFactory.java @@ -85,6 +85,12 @@ class AdHocSearchChildFactory extends ChildFactory { private final Collection queryRequests; private final boolean saveResults; + /** + * Constructor + * + * @param queryRequests Query results + * @param saveResults Flag whether to save search results as KWS artifacts. + */ AdHocSearchChildFactory(Collection queryRequests, boolean saveResults) { this.queryRequests = queryRequests; this.saveResults = saveResults; diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/AdHocSearchDelegator.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/AdHocSearchDelegator.java index 4b9a229785..a79f050ee2 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/AdHocSearchDelegator.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/AdHocSearchDelegator.java @@ -74,6 +74,8 @@ class AdHocSearchDelegator { /** * Execute the keyword search based on keywords passed into constructor. * Post results into a new DataResultViewer. + * + * @param saveResults Flag whether to save search results as KWS artifacts. */ public void execute(boolean saveResults) { Collection queryRequests = new ArrayList<>(); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/AdHocSearchPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/AdHocSearchPanel.java index ec75de032e..6190f392e8 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/AdHocSearchPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/AdHocSearchPanel.java @@ -98,6 +98,8 @@ abstract class AdHocSearchPanel extends javax.swing.JPanel { /** * Performs the search using the selected keywords. Creates a * DataResultTopComponent with the results. + * + * @param saveResults Flag whether to save search results as KWS artifacts. */ public void search(boolean saveResults) { boolean isIngestRunning = IngestManager.getInstance().isIngestRunning(); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryResults.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryResults.java index 5f672f5f03..66d0803812 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryResults.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryResults.java @@ -141,6 +141,7 @@ class QueryResults { * @param notifyInbox Whether or not to write a message to the ingest * messages inbox if there is a keyword hit in the text * exrtacted from the text source object. + * @param saveResults Flag whether to save search results as KWS artifacts. * */ void process(ProgressHandle progress, ProgressContributor subProgress, SwingWorker worker, boolean notifyInbox, boolean saveResults) { @@ -220,14 +221,13 @@ class QueryResults { } if (saveResults) { - /* - * Post an artifact for the hit to the blackboard. + * Post an artifact for the hit to the blackboard. */ BlackboardArtifact artifact = query.postKeywordHitToBlackboard(content, keyword, hit, snippet, query.getKeywordList().getName()); /* - * Send an ingest inbox message for the hit. + * Send an ingest inbox message for the hit. */ if (null != artifact) { hitArtifacts.add(artifact); From 1ae1c34dd27055808502a5b177b562b71007de23 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Wed, 25 Jul 2018 15:37:46 -0400 Subject: [PATCH 042/105] Fixed spelling errors --- .../src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties index 144609972d..eedf0cb8ec 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties @@ -313,7 +313,7 @@ ExtractedContentPanel.pagesLabel.text=Page: DropdownSingleTermSearchPanel.dataSourceCheckBox.text=Restrict search to the selected data sources: DropdownListSearchPanel.dataSourceCheckBox.text=Restrict search to the selected data sources: DropdownSingleTermSearchPanel.ingestIndexLabel.text=Files Indexed: -DropdownSingleTermSearchPanel.jSaveSearchResults.toolTipText=Performe keyword search without saving the results in the form of keyword hit artifacts +DropdownSingleTermSearchPanel.jSaveSearchResults.toolTipText=Perform keyword search without saving the results in the form of keyword hit artifacts DropdownSingleTermSearchPanel.jSaveSearchResults.text=Save search results -DropdownListSearchPanel.jSaveSearchResults.toolTipText=Performe keyword search without saving the results in the form of keyword hit artifacts +DropdownListSearchPanel.jSaveSearchResults.toolTipText=Perform keyword search without saving the results in the form of keyword hit artifacts DropdownListSearchPanel.jSaveSearchResults.text=Save search results From 04cc3de2195767439acb6632e4117467ee575492 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 25 Jul 2018 15:52:57 -0400 Subject: [PATCH 043/105] Added code to prevent duplicate hash set hits; general cleanup. --- .../casemodule/services/Blackboard.java | 112 +++++++++- .../modules/hashdatabase/Bundle.properties | 19 -- .../modules/hashdatabase/Bundle_ja.properties | 23 --- .../hashdatabase/HashDbIngestModule.java | 192 ++++++++++++------ .../hashdatabase/HashLookupModuleFactory.java | 26 +-- 5 files changed, 250 insertions(+), 122 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Blackboard.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/Blackboard.java index 58b4f41d6e..ee4718e8d2 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Blackboard.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Blackboard.java @@ -20,9 +20,15 @@ package org.sleuthkit.autopsy.casemodule.services; import java.io.Closeable; import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService; +import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.SleuthkitCase; @@ -38,7 +44,7 @@ import org.sleuthkit.datamodel.TskDataException; public final class Blackboard implements Closeable { private SleuthkitCase caseDb; - + /** * Constructs a representation of the blackboard, a place where artifacts * and their attributes are posted. @@ -80,8 +86,8 @@ public final class Blackboard implements Closeable { * * @return A type object representing the artifact type. * - * @throws BlackboardBlackboardException If there is a problem getting or - * adding the artifact type. + * @throws BlackboardException If there is a problem getting or adding the + * artifact type. */ public synchronized BlackboardArtifact.Type getOrAddArtifactType(String typeName, String displayName) throws BlackboardException { if (null == caseDb) { @@ -110,8 +116,8 @@ public final class Blackboard implements Closeable { * * @return A type object representing the attribute type. * - * @throws BlackboardBlackboardException If there is a problem getting or - * adding the attribute type. + * @throws BlackboardException If there is a problem getting or adding the + * attribute type. */ public synchronized BlackboardAttribute.Type getOrAddAttributeType(String typeName, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName) throws BlackboardException { if (null == caseDb) { @@ -130,6 +136,101 @@ public final class Blackboard implements Closeable { } } + /** + * Determine if an artifact of a given type exists for a given file with a + * specific set of attributes. + * + * @param file The file whose artifacts need to be looked at. + * @param artifactType The type of artifact to look for. + * @param attributesMap The collection of attributes to look for. + * + * @return True if the specific artifact exists; otherwise false. + * + * @throws BlackboardException If there is a problem getting artifacts or + * attributes. + */ + public static boolean checkIfArtifactExists(AbstractFile file, BlackboardArtifact.ARTIFACT_TYPE artifactType, + Map attributesMap) throws BlackboardException { + + ArrayList artifactsList; + + /* + * Get the file's artifacts. + */ + try { + artifactsList = file.getArtifacts(artifactType); + if (artifactsList.isEmpty()) { + return false; + } + } catch (TskCoreException ex) { + throw new BlackboardException(String.format("Failed to get %s artifacts for file '%s' (id=%d).", + artifactType.getDisplayName(), file.getName(), file.getId()), ex); + } + + /* + * Get each artifact's attributes and analyze them for matches. + */ + for (BlackboardArtifact artifact : artifactsList) { + try { + if (checkIfAttributesMatch(artifact.getAttributes(), attributesMap)) { + /* + * The exact artifact exists, so we don't need to look at + * further. + */ + return true; + } + } catch (TskCoreException ex) { + throw new BlackboardException(String.format("Failed to get attributes from artifact '%s' (id=%d).", + artifact.getName(), artifact.getObjectID()), ex); + } + } + + /* + * None of the artifacts have the exact set of attribute type/value + * combinations. The provided file does not the artifact being sought. + */ + return false; + } + + /** + * Determine if a list of attributes all match a given set of values. + * + * @param attributesList The list of attributes to analyze. + * @param attributesMap The attribute values with which to compare. + * + * @return True if all attributes match; otherwise false. + */ + private static boolean checkIfAttributesMatch(List attributesList, Map attributesMap) { + for (Map.Entry mapEntry : attributesMap.entrySet()) { + boolean match = false; + for (BlackboardAttribute attribute : attributesList) { + BlackboardAttribute.Type attributeType = attribute.getAttributeType(); + String attributeValue = attribute.getValueString(); + if (attributeType.getTypeID() == mapEntry.getKey().getTypeID() && attributeValue.equals(mapEntry.getValue())) { + /* + * The exact attribute type/value combination was found. + * Mark this as a match to continue looping through the + * attributes map. + */ + match = true; + break; + } + } + if (!match) { + /* + * The exact attribute type/value combination was not found. + */ + return false; + } + }; + + /* + * All attribute type/value combinations were found in the provided + * attributes list. + */ + return true; + } + /** * Closes the blackboard. * @@ -140,7 +241,6 @@ public final class Blackboard implements Closeable { caseDb = null; } - /** * A blackboard exception. */ diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties index c5f6d82425..3ca6c162b6 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties @@ -87,23 +87,6 @@ HashDbImportDatabaseDialog.importHashDbErr=Import Hash Set Error HashDbImportDatabaseDialog.mustSelectHashDbFilePathMsg=A hash set file path must be selected. HashDbImportDatabaseDialog.hashDbDoesNotExistMsg=The selected hash set does not exist. HashDbImportDatabaseDialog.errorMessage.failedToOpenHashDbMsg=Failed to open hash set at {0}. -HashDbIngestModule.moduleName=Hash Lookup -HashDbIngestModule.moduleDescription=Identifies known and notable files using supplied hash sets, such as a standard NSRL hash set. -HashDbIngestModule.fileReadErrorMsg=Read Error\: {0} -HashDbIngestModule.calcHashValueErr=Error encountered while calculating the hash value for {0}. -HashDbIngestModule.hashLookupErrorMsg=Hash Lookup Error\: {0} -HashDbIngestModule.settingKnownBadStateErr=Error encountered while setting notable state for {0}. -HashDbIngestModule.lookingUpKnownBadHashValueErr=Error encountered while looking up notable hash value for {0}. -HashDbIngestModule.lookingUpKnownHashValueErr=Error encountered while looking up known hash value for {0}. -HashDbIngestModule.postToBB.fileName=File Name -HashDbIngestModule.postToBB.md5Hash=MD5 Hash -HashDbIngestModule.postToBB.hashsetName=Hash Set Name -HashDbIngestModule.postToBB.knownBadMsg=Notable\: {0} -HashDbIngestModule.complete.knownBadsFound=Notables found\: -HashDbIngestModule.complete.totalCalcTime=Total Calculation Time -HashDbIngestModule.complete.totalLookupTime=Total Lookup Time -HashDbIngestModule.complete.databasesUsed=Hash Sets Used\: -HashDbIngestModule.complete.hashLookupResults=Hash Lookup Results HashDbManager.moduleErrorListeningToUpdatesMsg=A module caused an error listening to HashDbManager updates. See log to determine which module. Some data could be incomplete. HashDbManager.replacingDuplicateHashsetNameMsg=Duplicate hash set name {0} found.\nReplacing with {1}. HashDbManager.openHashDbErr=Open Hash Set Error @@ -165,8 +148,6 @@ AddContentToHashDbAction.addFilesToHashSet.files=files AddContentToHashDbAction.addFilesToHashSet.file=file HashDbManager.errCreatingIndex.title=Error creating index HashDbManager.errCreatingIndex.msg=Error creating index\: {0} -HashLookupModuleFactory.getIngestJobSettingsPanel.exception.msg=Expected settings argument to be instanceof HashLookupModuleSettings -HashLookupModuleFactory.createFileIngestModule.exception.msg=Expected settings argument to be instanceof HashLookupModuleSettings HashLookupModuleSettingsPanel.alwaysCalcHashesCheckbox.toolTipText=Calculate MD5 even if no hash set is selected HashDbSearchPanel.hashTable.defaultModel.title.text=MD5 Hashes AddHashValuesToDatabaseDialog.JDialog.Title=Add Hashes to Hash Set diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties index 828b027bdb..3d2ab7a085 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties @@ -76,28 +76,7 @@ HashDbImportDatabaseDialog.importHashDbErr=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\ HashDbImportDatabaseDialog.mustSelectHashDbFilePathMsg=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u30d5\u30a1\u30a4\u30eb\u30d1\u30b9\u306e\u9078\u629e\u304c\u5fc5\u8981\u3067\u3059\u3002 HashDbImportDatabaseDialog.hashDbDoesNotExistMsg=\u9078\u629e\u3055\u308c\u305f\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306f\u5b58\u5728\u3057\u307e\u305b\u3093\u3002 HashDbImportDatabaseDialog.errorMessage.failedToOpenHashDbMsg={0}\u3067\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u958b\u304f\u306e\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 -HashDbIngestModule.moduleName=\u30cf\u30c3\u30b7\u30e5\u30eb\u30c3\u30af\u30a2\u30c3\u30d7 -HashDbIngestModule.moduleDescription=\u6a19\u6e96\u306eNSRL\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306a\u3069\u3001\u63d0\u4f9b\u3055\u308c\u305f\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u5229\u7528\u3057\u3066\u3001\u65e2\u77e5\u307e\u305f\u306f\u7591\u308f\u3057\u3044\u3082\u306e\u3092\u691c\u77e5\u3057\u307e\u3059\u3002 -HashDbIngestModule.noKnownHashDbSetMsg=\u65e2\u77e5\u306e\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u5b58\u5728\u3057\u307e\u305b\u3093\u3002 -HashDbIngestModule.knownFileSearchWillNotExecuteWarn=\u65e2\u77e5\u306e\u30d5\u30a1\u30a4\u30eb\u691c\u7d22\u304c\u5b9f\u884c\u3055\u308c\u307e\u305b\u3093\u3002 -HashDbIngestModule.noKnownBadHashDbSetMsg=\u65e2\u77e5\u306e\u60aa\u8cea\u306a\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30bb\u30c3\u30c8\u306f\u3042\u308a\u307e\u305b\u3093\u3002 HashDbConfigPanel.dbNotIndexedMsg=\u6b21\u306e\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306f\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5316\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5316\u3057\u307e\u3059\u304b\uff1f\n{0} -HashDbIngestModule.knownBadFileSearchWillNotExecuteWarn=\u65e2\u77e5\u306e\u60aa\u8cea\u30d5\u30a1\u30a4\u30eb\u691c\u7d22\u306f\u5b9f\u884c\u3055\u308c\u307e\u305b\u3093\u3002 -HashDbIngestModule.fileReadErrorMsg=\u8aad\u307f\u8fbc\u307f\u30a8\u30e9\u30fc\uff1a {0} -HashDbIngestModule.calcHashValueErr={0}\u306e\u30cf\u30c3\u30b7\u30e5\u5024\u3092\u8a08\u7b97\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 -HashDbIngestModule.hashLookupErrorMsg=\u30cf\u30c3\u30b7\u30e5\u30eb\u30c3\u30af\u30a2\u30c3\u30d7\u30a8\u30e9\u30fc\uff1a {0} -HashDbIngestModule.settingKnownBadStateErr={0}\u306e\u65e2\u77e5\u306e\u60aa\u8cea\u30b9\u30c6\u30fc\u30bf\u30b9\u3092\u8a2d\u5b9a\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 -HashDbIngestModule.lookingUpKnownBadHashValueErr={0}\u306e\u65e2\u77e5\u306e\u60aa\u8cea\u30cf\u30c3\u30b7\u30e5\u5024\u3092\u30eb\u30c3\u30af\u30a2\u30c3\u30d7\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 -HashDbIngestModule.lookingUpKnownHashValueErr={0}\u306e\u65e2\u77e5\u306e\u30cf\u30c3\u30b7\u30e5\u5024\u3092\u30eb\u30c3\u30af\u30a2\u30c3\u30d7\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 -HashDbIngestModule.postToBB.fileName=\u30d5\u30a1\u30a4\u30eb\u540d -HashDbIngestModule.postToBB.md5Hash=MD5\u30cf\u30c3\u30b7\u30e5 -HashDbIngestModule.postToBB.hashsetName=\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u540d -HashDbIngestModule.postToBB.knownBadMsg=\u65e2\u77e5\u306e\u60aa\u8cea\: {0} -HashDbIngestModule.complete.knownBadsFound=\u767a\u898b\u3055\u308c\u305f\u65e2\u77e5\u306e\u60aa\u8cea\uff1a -HashDbIngestModule.complete.totalCalcTime=\u8a08\u7b97\u6642\u9593\u306e\u5408\u8a08 -HashDbIngestModule.complete.totalLookupTime=\u30eb\u30c3\u30af\u30a2\u30c3\u30d7\u6642\u9593\u306e\u5408\u8a08 -HashDbIngestModule.complete.databasesUsed=\u5229\u7528\u3057\u305f\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\uff1a -HashDbIngestModule.complete.hashLookupResults=\u30cf\u30c3\u30b7\u30e5\u30eb\u30c3\u30af\u30a2\u30c3\u30d7\u7d50\u679c HashDbManager.moduleErrorListeningToUpdatesMsg=HashDbManager\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u3092\u78ba\u8a8d\u4e2d\u306b\u30e2\u30b8\u30e5\u30fc\u30eb\u304c\u30a8\u30e9\u30fc\u3092\u8d77\u3053\u3057\u307e\u3057\u305f\u3002\u3069\u306e\u30e2\u30b8\u30e5\u30fc\u30eb\u304c\u539f\u56e0\u306a\u306e\u304b\u3092\u30ed\u30b0\u3092\u78ba\u8a8d\u3057\u3066\u4e0b\u3055\u3044\u3002\u4e00\u90e8\u306e\u30c7\u30fc\u30bf\u304c\u5b8c\u5168\u3067\u306a\u3044\u3053\u3068\u304c\u3042\u308a\u307e\u3059\u3002 HashDbManager.replacingDuplicateHashsetNameMsg=\u91cd\u8907\u306e\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u540d {0} \u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f\u3002\n {1}\u306b\u66f8\u304d\u63db\u3048\u307e\u3059\u3002 HashDbManager.openHashDbErr=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u958b\u304f\u30a8\u30e9\u30fc @@ -163,8 +142,6 @@ HashLookupSettingsPanel.jLabel2.text=\u540d\u524d\uff1a HashLookupModuleSettingsPanel.alwaysCalcHashesCheckbox.text=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u306a\u304f\u3066\u3082\u3001MD5\u3092\u8a08\u7b97 HashLookupModuleSettingsPanel.knownHashDbsLabel.text=\u5229\u7528\u3059\u308b\u65e2\u77e5\u306e\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u9078\u629e\uff1a HashLookupModuleSettingsPanel.knownBadHashDbsLabel.text=\u51e6\u7406\u306b\u5229\u7528\u3059\u308b\u65e2\u77e5\u306e\u60aa\u8cea\u306a\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u9078\u629e\uff1a -HashLookupModuleFactory.createFileIngestModule.exception.msg=\u8a2d\u5b9a\u3092\u884c\u3046\u70ba\u306e\u60f3\u5b9a\u3055\u308c\u308b\u5f15\u6570\u306finstanceof HashLookupModuleSettings\u3067\u3059\u3002 -HashLookupModuleFactory.getIngestJobSettingsPanel.exception.msg=\u8a2d\u5b9a\u3092\u884c\u3046\u70ba\u306e\u60f3\u5b9a\u3055\u308c\u308b\u5f15\u6570\u306finstanceof HashLookupModuleSettings\u3067\u3059\u3002 HashLookupModuleSettingsPanel.alwaysCalcHashesCheckbox.toolTipText=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u306a\u304f\u3066\u3082\u3001MD5\u3092\u8a08\u7b97 HashDbSearchPanel.hashTable.defaultModel.title.text=MD5\u30cf\u30c3\u30b7\u30e5 AddContentToHashDbAction.addFilesToHashSet.unableToAddFileEmptyMsg=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306b{0}\u3092\u8ffd\u52a0\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30d5\u30a1\u30a4\u30eb\u306b\u30b3\u30f3\u30c6\u30f3\u30c4\u304c\u3042\u308a\u307e\u305b\u3093\u3002 diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java index 74387840b5..2a134a7fe7 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 - 2013 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,13 +24,14 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.Map; 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.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.Blackboard; +import org.sleuthkit.autopsy.casemodule.services.Blackboard.BlackboardException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.healthmonitor.HealthMonitor; @@ -48,37 +49,35 @@ 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; -@NbBundle.Messages({ - "HashDbIngestModule.noKnownBadHashDbSetMsg=No notable hash set.", - "HashDbIngestModule.knownBadFileSearchWillNotExecuteWarn=Notable file search will not be executed.", - "HashDbIngestModule.noKnownHashDbSetMsg=No known hash set.", - "HashDbIngestModule.knownFileSearchWillNotExecuteWarn=Known file search will not be executed." -}) +/** + * File ingest module to mark files based on hash values. + */ public class HashDbIngestModule implements FileIngestModule { private static final Logger logger = Logger.getLogger(HashDbIngestModule.class.getName()); private static final int MAX_COMMENT_SIZE = 500; private final IngestServices services = IngestServices.getInstance(); - private final SleuthkitCase skCase; private final HashDbManager hashDbManager = HashDbManager.getInstance(); private final HashLookupModuleSettings settings; - private List knownBadHashSets = new ArrayList<>(); - private List knownHashSets = new ArrayList<>(); + private final List knownBadHashSets = new ArrayList<>(); + private final List knownHashSets = new ArrayList<>(); private long jobId; private static final HashMap totalsForIngestJobs = new HashMap<>(); private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter(); private Blackboard blackboard; + /** + * A container of values for storing ingest metrics for the job. + */ private static class IngestJobTotals { - private AtomicLong totalKnownBadCount = new AtomicLong(0); - private AtomicLong totalCalctime = new AtomicLong(0); - private AtomicLong totalLookuptime = new AtomicLong(0); + private final AtomicLong totalKnownBadCount = new AtomicLong(0); + private final AtomicLong totalCalctime = new AtomicLong(0); + private final AtomicLong totalLookuptime = new AtomicLong(0); } private static synchronized IngestJobTotals getTotalsForIngestJobs(long ingestJobId) { @@ -90,11 +89,23 @@ public class HashDbIngestModule implements FileIngestModule { return totals; } - HashDbIngestModule(HashLookupModuleSettings settings) throws NoCurrentCaseException { + /** + * Create a HashDbIngestModule object that will mark files based on a + * supplied list of hash values. The supplied HashLookupModuleSettings + * object is used to configure the module. + * + * @param settings The module settings. + */ + HashDbIngestModule(HashLookupModuleSettings settings) { this.settings = settings; - skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); } + @Messages({ + "HashDbIngestModule.noKnownBadHashDbSetMsg=No notable hash set.", + "HashDbIngestModule.knownBadFileSearchWillNotExecuteWarn=Notable file search will not be executed.", + "HashDbIngestModule.noKnownHashDbSetMsg=No known hash set.", + "HashDbIngestModule.knownFileSearchWillNotExecuteWarn=Known file search will not be executed." + }) @Override public void startUp(org.sleuthkit.autopsy.ingest.IngestJobContext context) throws IngestModuleException { jobId = context.getJobId(); @@ -140,12 +151,34 @@ public class HashDbIngestModule implements FileIngestModule { enabledHashSets.add(db); } } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Error getting index status for " + db.getDisplayName()+ " hash set", ex); //NON-NLS + logger.log(Level.WARNING, "Error getting index status for " + db.getDisplayName() + " hash set", ex); //NON-NLS } } } } + @Messages({ + "# {0} - File name", + "HashDbIngestModule.fileReadErrorMsg=Read Error: {0}", + + "# {0} - File name", + "HashDbIngestModule.calcHashValueErr=Error encountered while calculating the hash value for {0}.", + + "# {0} - File name", + "HashDbIngestModule.hashLookupErrorMsg=Hash Lookup Error: {0}", + + "# {0} - File name", + "HashDbIngestModule.lookingUpKnownBadHashValueErr=Error encountered while looking up notable hash value for {0}.", + + "# {0} - File name", + "HashDbIngestModule.lookingUpKnownHashValueErr=Error encountered while looking up known hash value for {0}.", + + "# {0} - File name", + "HashDbIngestModule.dialogTitle.errorFindingArtifacts=Error Finding Artifacts: {0}", + + "# {0} - File name", + "HashDbIngestModule.errorMessage.lookingForFileArtifacts=Error encountered while looking for existing artifacts for {0}." + }) @Override public ProcessResult process(AbstractFile file) { try { @@ -156,8 +189,8 @@ public class HashDbIngestModule implements FileIngestModule { } // Skip unallocated space files. - if ((file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) || - file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK))) { + if ((file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) + || file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK))) { return ProcessResult.OK; } @@ -181,6 +214,7 @@ public class HashDbIngestModule implements FileIngestModule { // calc hash value String name = file.getName(); + long fileId = file.getId(); String md5Hash = file.getMd5Hash(); if (md5Hash == null || md5Hash.isEmpty()) { try { @@ -203,15 +237,11 @@ public class HashDbIngestModule implements FileIngestModule { totals.totalCalctime.addAndGet(delta); } catch (IOException ex) { - logger.log(Level.WARNING, "Error calculating hash of file " + name, ex); //NON-NLS + logger.log(Level.WARNING, String.format("Error calculating hash of file '%s' (id=%d).", name, fileId), ex); //NON-NLS services.postMessage(IngestMessage.createErrorMessage( HashLookupModuleFactory.getModuleName(), - NbBundle.getMessage(this.getClass(), - "HashDbIngestModule.fileReadErrorMsg", - name), - NbBundle.getMessage(this.getClass(), - "HashDbIngestModule.calcHashValueErr", - name))); + Bundle.HashDbIngestModule_fileReadErrorMsg(name), + Bundle.HashDbIngestModule_calcHashValueErr(name))); return ProcessResult.ERROR; } } @@ -245,21 +275,34 @@ public class HashDbIngestModule implements FileIngestModule { } } - postHashSetHitToBlackboard(file, md5Hash, hashSetName, comment, db.getSendIngestMessages()); + /* + * We have a match! Now create an artifact for it is + * determined that one hasn't been created yet. + */ + Map attributeMap = new HashMap<>(); + attributeMap.put(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SET_NAME), hashSetName); + if (!Blackboard.checkIfArtifactExists(file, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT, attributeMap)) { + postHashSetHitToBlackboard(file, md5Hash, hashSetName, comment, db.getSendIngestMessages()); + } } long delta = (System.currentTimeMillis() - lookupstart); totals.totalLookuptime.addAndGet(delta); - } catch (TskException ex) { - logger.log(Level.WARNING, "Couldn't lookup notable hash for file " + name + " - see sleuthkit log for details", ex); //NON-NLS + } catch (BlackboardException ex) { + logger.log(Level.SEVERE, String.format( + "A problem occurred while trying checking for existing artifacts for file '%s' (id=%d).", name, fileId), ex); //NON-NLS services.postMessage(IngestMessage.createErrorMessage( HashLookupModuleFactory.getModuleName(), - NbBundle.getMessage(this.getClass(), - "HashDbIngestModule.hashLookupErrorMsg", - name), - NbBundle.getMessage(this.getClass(), - "HashDbIngestModule.lookingUpKnownBadHashValueErr", - name))); + Bundle.HashDbIngestModule_dialogTitle_errorFindingArtifacts(name), + Bundle.HashDbIngestModule_errorMessage_lookingForFileArtifacts(name))); + ret = ProcessResult.ERROR; + } catch (TskException ex) { + logger.log(Level.WARNING, String.format( + "Couldn't lookup notable hash for file '%s' (id=%d) - see sleuthkit log for details", name, fileId), ex); //NON-NLS + services.postMessage(IngestMessage.createErrorMessage( + HashLookupModuleFactory.getModuleName(), + Bundle.HashDbIngestModule_hashLookupErrorMsg(name), + Bundle.HashDbIngestModule_lookingUpKnownBadHashValueErr(name))); ret = ProcessResult.ERROR; } } @@ -279,15 +322,12 @@ public class HashDbIngestModule implements FileIngestModule { totals.totalLookuptime.addAndGet(delta); } catch (TskException ex) { - logger.log(Level.WARNING, "Couldn't lookup known hash for file " + name + " - see sleuthkit log for details", ex); //NON-NLS + logger.log(Level.WARNING, String.format( + "Couldn't lookup known hash for file '%s' (id=%d) - see sleuthkit log for details", name, fileId), ex); //NON-NLS services.postMessage(IngestMessage.createErrorMessage( HashLookupModuleFactory.getModuleName(), - NbBundle.getMessage(this.getClass(), - "HashDbIngestModule.hashLookupErrorMsg", - name), - NbBundle.getMessage(this.getClass(), - "HashDbIngestModule.lookingUpKnownHashValueErr", - name))); + Bundle.HashDbIngestModule_hashLookupErrorMsg(name), + Bundle.HashDbIngestModule_lookingUpKnownHashValueErr(name))); ret = ProcessResult.ERROR; } } @@ -296,18 +336,35 @@ public class HashDbIngestModule implements FileIngestModule { return ret; } - @Messages({"HashDbIngestModule.indexError.message=Failed to index hashset hit artifact for keyword search."}) + /** + * Post hash set hit to the blackboard. + * + * @param abstractFile The file to be processed. + * @param md5Hash The MD5 hash value of the file. + * @param hashSetName The name of the hash set with which to associate + * the hit. + * @param comment A comment to be attached to the artifact. + * @param showInboxMessage Show a message in the inbox? + */ + @Messages({ + "HashDbIngestModule.indexError.message=Failed to index hashset hit artifact for keyword search.", + "HashDbIngestModule.postToBB.fileName=File Name", + "HashDbIngestModule.postToBB.md5Hash=MD5 Hash", + "HashDbIngestModule.postToBB.hashsetName=Hash Set Name", + + "# {0} - File name", + "HashDbIngestModule.postToBB.knownBadMsg=Notable: {0}" + }) private void postHashSetHitToBlackboard(AbstractFile abstractFile, String md5Hash, String hashSetName, String comment, boolean showInboxMessage) { try { - String MODULE_NAME = NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.moduleName"); - + String moduleName = HashLookupModuleFactory.getModuleName(); BlackboardArtifact badFile = abstractFile.newArtifact(ARTIFACT_TYPE.TSK_HASHSET_HIT); Collection attributes = new ArrayList<>(); //TODO Revisit usage of deprecated constructor as per TSK-583 //BlackboardAttribute att2 = new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID(), MODULE_NAME, "Known Bad", hashSetName); - attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, hashSetName)); - attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_HASH_MD5, MODULE_NAME, md5Hash)); - attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT, MODULE_NAME, comment)); + attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, moduleName, hashSetName)); + attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_HASH_MD5, moduleName, md5Hash)); + attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT, moduleName, comment)); badFile.addAttributes(attributes); @@ -327,7 +384,7 @@ public class HashDbIngestModule implements FileIngestModule { //hit detailsSb.append(""); //NON-NLS detailsSb.append("") //NON-NLS - .append(NbBundle.getMessage(this.getClass(), "HashDbIngestModule.postToBB.fileName")) + .append(Bundle.HashDbIngestModule_postToBB_fileName()) .append(""); //NON-NLS detailsSb.append("") //NON-NLS .append(abstractFile.getName()) @@ -336,14 +393,14 @@ public class HashDbIngestModule implements FileIngestModule { detailsSb.append(""); //NON-NLS detailsSb.append("") //NON-NLS - .append(NbBundle.getMessage(this.getClass(), "HashDbIngestModule.postToBB.md5Hash")) + .append(Bundle.HashDbIngestModule_postToBB_md5Hash()) .append(""); //NON-NLS detailsSb.append("").append(md5Hash).append(""); //NON-NLS detailsSb.append(""); //NON-NLS detailsSb.append(""); //NON-NLS detailsSb.append("") //NON-NLS - .append(NbBundle.getMessage(this.getClass(), "HashDbIngestModule.postToBB.hashsetName")) + .append(Bundle.HashDbIngestModule_postToBB_hashsetName()) .append(""); //NON-NLS detailsSb.append("").append(hashSetName).append(""); //NON-NLS detailsSb.append(""); //NON-NLS @@ -351,19 +408,31 @@ public class HashDbIngestModule implements FileIngestModule { detailsSb.append(""); //NON-NLS services.postMessage(IngestMessage.createDataMessage(HashLookupModuleFactory.getModuleName(), - NbBundle.getMessage(this.getClass(), - "HashDbIngestModule.postToBB.knownBadMsg", - abstractFile.getName()), + Bundle.HashDbIngestModule_postToBB_knownBadMsg(abstractFile.getName()), detailsSb.toString(), abstractFile.getName() + md5Hash, badFile)); } - services.fireModuleDataEvent(new ModuleDataEvent(MODULE_NAME, ARTIFACT_TYPE.TSK_HASHSET_HIT, Collections.singletonList(badFile))); + services.fireModuleDataEvent(new ModuleDataEvent(moduleName, ARTIFACT_TYPE.TSK_HASHSET_HIT, Collections.singletonList(badFile))); } catch (TskException ex) { logger.log(Level.WARNING, "Error creating blackboard artifact", ex); //NON-NLS } } + /** + * Post a message summarizing the results of the ingest. + * + * @param jobId The ID of the job. + * @param knownBadHashSets The list of hash sets for "known bad" files. + * @param knownHashSets The list of hash sets for "known" files. + */ + @Messages({ + "HashDbIngestModule.complete.knownBadsFound=Notables found:", + "HashDbIngestModule.complete.totalCalcTime=Total Calculation Time", + "HashDbIngestModule.complete.totalLookupTime=Total Lookup Time", + "HashDbIngestModule.complete.databasesUsed=Hash Sets Used:", + "HashDbIngestModule.complete.hashLookupResults=Hash Lookup Results" + }) private static synchronized void postSummary(long jobId, List knownBadHashSets, List knownHashSets) { IngestJobTotals jobTotals = getTotalsForIngestJobs(jobId); @@ -375,20 +444,20 @@ public class HashDbIngestModule implements FileIngestModule { detailsSb.append(""); //NON-NLS detailsSb.append(""); //NON-NLS detailsSb.append(""); //NON-NLS detailsSb.append("\n"); //NON-NLS detailsSb.append("\n"); //NON-NLS detailsSb.append("
") //NON-NLS - .append(NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.complete.knownBadsFound")) + .append(Bundle.HashDbIngestModule_complete_knownBadsFound()) .append("").append(jobTotals.totalKnownBadCount.get()).append("
") //NON-NLS - .append(NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.complete.totalCalcTime")) + .append(Bundle.HashDbIngestModule_complete_totalCalcTime()) .append("").append(jobTotals.totalCalctime.get()).append("
") //NON-NLS - .append(NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.complete.totalLookupTime")) + .append(Bundle.HashDbIngestModule_complete_totalLookupTime()) .append("").append(jobTotals.totalLookuptime.get()).append("
"); //NON-NLS detailsSb.append("

") //NON-NLS - .append(NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.complete.databasesUsed")) + .append(Bundle.HashDbIngestModule_complete_databasesUsed()) .append("

\n
    "); //NON-NLS for (HashDb db : knownBadHashSets) { detailsSb.append("
  • ").append(db.getHashSetName()).append("
  • \n"); //NON-NLS @@ -399,8 +468,7 @@ public class HashDbIngestModule implements FileIngestModule { IngestServices.getInstance().postMessage(IngestMessage.createMessage( IngestMessage.MessageType.INFO, HashLookupModuleFactory.getModuleName(), - NbBundle.getMessage(HashDbIngestModule.class, - "HashDbIngestModule.complete.hashLookupResults"), + Bundle.HashDbIngestModule_complete_hashLookupResults(), detailsSb.toString())); } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java index 068c52cf5e..a327a659af 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java @@ -20,7 +20,6 @@ package org.sleuthkit.autopsy.modules.hashdatabase; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Version; import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter; import org.sleuthkit.autopsy.ingest.FileIngestModule; @@ -33,6 +32,10 @@ import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel; * A factory that creates file ingest modules that do hash database lookups. */ @ServiceProvider(service = IngestModuleFactory.class) +@NbBundle.Messages({ + "HashLookupModuleFactory.moduleName.text=Hash Lookup", + "HashLookupModuleFactory.moduleDescription.text=Identifies known and notable files using supplied hash sets, such as a standard NSRL hash set." +}) public class HashLookupModuleFactory extends IngestModuleFactoryAdapter { private HashLookupModuleSettingsPanel moduleSettingsPanel = null; @@ -42,13 +45,18 @@ public class HashLookupModuleFactory extends IngestModuleFactoryAdapter { return getModuleName(); } + /** + * Get the name of the module. + * + * @return The module name. + */ static String getModuleName() { - return NbBundle.getMessage(HashLookupModuleFactory.class, "HashDbIngestModule.moduleName"); + return Bundle.HashLookupModuleFactory_moduleName_text(); } @Override public String getModuleDescription() { - return NbBundle.getMessage(HashLookupModuleFactory.class, "HashDbIngestModule.moduleDescription"); + return Bundle.HashLookupModuleFactory_moduleDescription_text(); } @Override @@ -70,8 +78,7 @@ public class HashLookupModuleFactory extends IngestModuleFactoryAdapter { @Override public IngestModuleIngestJobSettingsPanel getIngestJobSettingsPanel(IngestModuleIngestJobSettings settings) { if (!(settings instanceof HashLookupModuleSettings)) { - throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(), - "HashLookupModuleFactory.getIngestJobSettingsPanel.exception.msg")); + throw new IllegalArgumentException("Expected settings argument to be an instance of HashLookupModuleSettings."); } if (moduleSettingsPanel == null) { moduleSettingsPanel = new HashLookupModuleSettingsPanel((HashLookupModuleSettings) settings); @@ -101,13 +108,8 @@ public class HashLookupModuleFactory extends IngestModuleFactoryAdapter { @Override public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings settings) { if (!(settings instanceof HashLookupModuleSettings)) { - throw new IllegalArgumentException( - NbBundle.getMessage(this.getClass(), "HashLookupModuleFactory.createFileIngestModule.exception.msg")); - } - try { - return new HashDbIngestModule((HashLookupModuleSettings) settings); - } catch (NoCurrentCaseException ex) { - throw new IllegalArgumentException("Exception while getting open case.", ex); + throw new IllegalArgumentException("Expected settings argument to be an instance of HashLookupModuleSettings."); } + return new HashDbIngestModule((HashLookupModuleSettings) settings); } } From d11dbd7b3767c99800747568c52471b386a5182c Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 25 Jul 2018 16:17:19 -0400 Subject: [PATCH 044/105] Various typos fixed. --- .../autopsy/casemodule/services/Blackboard.java | 17 ++++++++--------- .../hashdatabase/HashDbIngestModule.java | 13 +++---------- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Blackboard.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/Blackboard.java index ee4718e8d2..234df7564b 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Blackboard.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Blackboard.java @@ -21,12 +21,9 @@ package org.sleuthkit.autopsy.casemodule.services; import java.io.Closeable; import java.io.IOException; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import java.util.Map; -import org.openide.util.Exceptions; import org.openide.util.Lookup; -import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -174,7 +171,7 @@ public final class Blackboard implements Closeable { try { if (checkIfAttributesMatch(artifact.getAttributes(), attributesMap)) { /* - * The exact artifact exists, so we don't need to look at + * The exact artifact exists, so we don't need to look any * further. */ return true; @@ -187,18 +184,20 @@ public final class Blackboard implements Closeable { /* * None of the artifacts have the exact set of attribute type/value - * combinations. The provided file does not the artifact being sought. + * combinations. The provided file does not have the artifact being + * sought. */ return false; } /** - * Determine if a list of attributes all match a given set of values. + * Determine if the supplied attribute type/value combinations can all be + * found in the supplied attributes list. * * @param attributesList The list of attributes to analyze. - * @param attributesMap The attribute values with which to compare. + * @param attributesMap The attribute type/value combinations to check for. * - * @return True if all attributes match; otherwise false. + * @return True if all attributes are found; otherwise false. */ private static boolean checkIfAttributesMatch(List attributesList, Map attributesMap) { for (Map.Entry mapEntry : attributesMap.entrySet()) { @@ -222,7 +221,7 @@ public final class Blackboard implements Closeable { */ return false; } - }; + } /* * All attribute type/value combinations were found in the provided diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java index 2a134a7fe7..d78713f23f 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java @@ -160,22 +160,16 @@ public class HashDbIngestModule implements FileIngestModule { @Messages({ "# {0} - File name", "HashDbIngestModule.fileReadErrorMsg=Read Error: {0}", - "# {0} - File name", "HashDbIngestModule.calcHashValueErr=Error encountered while calculating the hash value for {0}.", - "# {0} - File name", "HashDbIngestModule.hashLookupErrorMsg=Hash Lookup Error: {0}", - "# {0} - File name", "HashDbIngestModule.lookingUpKnownBadHashValueErr=Error encountered while looking up notable hash value for {0}.", - "# {0} - File name", "HashDbIngestModule.lookingUpKnownHashValueErr=Error encountered while looking up known hash value for {0}.", - "# {0} - File name", "HashDbIngestModule.dialogTitle.errorFindingArtifacts=Error Finding Artifacts: {0}", - "# {0} - File name", "HashDbIngestModule.errorMessage.lookingForFileArtifacts=Error encountered while looking for existing artifacts for {0}." }) @@ -276,7 +270,7 @@ public class HashDbIngestModule implements FileIngestModule { } /* - * We have a match! Now create an artifact for it is + * We have a match. Now create an artifact if it is * determined that one hasn't been created yet. */ Map attributeMap = new HashMap<>(); @@ -290,7 +284,7 @@ public class HashDbIngestModule implements FileIngestModule { } catch (BlackboardException ex) { logger.log(Level.SEVERE, String.format( - "A problem occurred while trying checking for existing artifacts for file '%s' (id=%d).", name, fileId), ex); //NON-NLS + "A problem occurred while checking for existing artifacts for file '%s' (id=%d).", name, fileId), ex); //NON-NLS services.postMessage(IngestMessage.createErrorMessage( HashLookupModuleFactory.getModuleName(), Bundle.HashDbIngestModule_dialogTitle_errorFindingArtifacts(name), @@ -337,7 +331,7 @@ public class HashDbIngestModule implements FileIngestModule { } /** - * Post hash set hit to the blackboard. + * Post a hash set hit to the blackboard. * * @param abstractFile The file to be processed. * @param md5Hash The MD5 hash value of the file. @@ -351,7 +345,6 @@ public class HashDbIngestModule implements FileIngestModule { "HashDbIngestModule.postToBB.fileName=File Name", "HashDbIngestModule.postToBB.md5Hash=MD5 Hash", "HashDbIngestModule.postToBB.hashsetName=Hash Set Name", - "# {0} - File name", "HashDbIngestModule.postToBB.knownBadMsg=Notable: {0}" }) From 3ea46cd32a810164b0066e9af371b875466dedd3 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Wed, 25 Jul 2018 16:48:57 -0400 Subject: [PATCH 045/105] Saving searches by default --- .../autopsy/keywordsearch/DropdownListSearchPanel.java | 2 ++ .../autopsy/keywordsearch/DropdownSingleTermSearchPanel.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownListSearchPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownListSearchPanel.java index 12a0ae9b4f..a8a9a93fc6 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownListSearchPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownListSearchPanel.java @@ -164,6 +164,8 @@ class DropdownListSearchPanel extends AdHocSearchPanel { } listsTableModel.resync(); updateIngestIndexLabel(); + + jSaveSearchResults.setSelected(true); } private void updateIngestIndexLabel() { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.java index 3e33e73a5c..1f6744cced 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.java @@ -120,6 +120,8 @@ public class DropdownSingleTermSearchPanel extends AdHocSearchPanel { }; ingestRunning = IngestManager.getInstance().isIngestRunning(); updateIngestIndexLabel(); + + jSaveSearchResults.setSelected(true); IngestManager.getInstance().addIngestJobEventListener(new PropertyChangeListener() { @Override From fa246542f6ab9691888b0344b7e2d8033ea9253a Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 25 Jul 2018 16:57:52 -0400 Subject: [PATCH 046/105] Further cleanup. --- .../casemodule/services/Blackboard.java | 101 ------------------ .../hashdatabase/HashDbIngestModule.java | 23 ++-- 2 files changed, 12 insertions(+), 112 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Blackboard.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/Blackboard.java index 234df7564b..6e954ce725 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Blackboard.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Blackboard.java @@ -20,12 +20,8 @@ package org.sleuthkit.autopsy.casemodule.services; import java.io.Closeable; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; import org.openide.util.Lookup; import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService; -import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.SleuthkitCase; @@ -133,103 +129,6 @@ public final class Blackboard implements Closeable { } } - /** - * Determine if an artifact of a given type exists for a given file with a - * specific set of attributes. - * - * @param file The file whose artifacts need to be looked at. - * @param artifactType The type of artifact to look for. - * @param attributesMap The collection of attributes to look for. - * - * @return True if the specific artifact exists; otherwise false. - * - * @throws BlackboardException If there is a problem getting artifacts or - * attributes. - */ - public static boolean checkIfArtifactExists(AbstractFile file, BlackboardArtifact.ARTIFACT_TYPE artifactType, - Map attributesMap) throws BlackboardException { - - ArrayList artifactsList; - - /* - * Get the file's artifacts. - */ - try { - artifactsList = file.getArtifacts(artifactType); - if (artifactsList.isEmpty()) { - return false; - } - } catch (TskCoreException ex) { - throw new BlackboardException(String.format("Failed to get %s artifacts for file '%s' (id=%d).", - artifactType.getDisplayName(), file.getName(), file.getId()), ex); - } - - /* - * Get each artifact's attributes and analyze them for matches. - */ - for (BlackboardArtifact artifact : artifactsList) { - try { - if (checkIfAttributesMatch(artifact.getAttributes(), attributesMap)) { - /* - * The exact artifact exists, so we don't need to look any - * further. - */ - return true; - } - } catch (TskCoreException ex) { - throw new BlackboardException(String.format("Failed to get attributes from artifact '%s' (id=%d).", - artifact.getName(), artifact.getObjectID()), ex); - } - } - - /* - * None of the artifacts have the exact set of attribute type/value - * combinations. The provided file does not have the artifact being - * sought. - */ - return false; - } - - /** - * Determine if the supplied attribute type/value combinations can all be - * found in the supplied attributes list. - * - * @param attributesList The list of attributes to analyze. - * @param attributesMap The attribute type/value combinations to check for. - * - * @return True if all attributes are found; otherwise false. - */ - private static boolean checkIfAttributesMatch(List attributesList, Map attributesMap) { - for (Map.Entry mapEntry : attributesMap.entrySet()) { - boolean match = false; - for (BlackboardAttribute attribute : attributesList) { - BlackboardAttribute.Type attributeType = attribute.getAttributeType(); - String attributeValue = attribute.getValueString(); - if (attributeType.getTypeID() == mapEntry.getKey().getTypeID() && attributeValue.equals(mapEntry.getValue())) { - /* - * The exact attribute type/value combination was found. - * Mark this as a match to continue looping through the - * attributes map. - */ - match = true; - break; - } - } - if (!match) { - /* - * The exact attribute type/value combination was not found. - */ - return false; - } - } - - /* - * All attribute type/value combinations were found in the provided - * attributes list. - */ - return true; - } - /** * Closes the blackboard. * diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java index d78713f23f..66ecf89aea 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java @@ -31,7 +31,6 @@ import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.Blackboard; -import org.sleuthkit.autopsy.casemodule.services.Blackboard.BlackboardException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.healthmonitor.HealthMonitor; @@ -275,21 +274,23 @@ public class HashDbIngestModule implements FileIngestModule { */ Map attributeMap = new HashMap<>(); attributeMap.put(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SET_NAME), hashSetName); - if (!Blackboard.checkIfArtifactExists(file, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT, attributeMap)) { - postHashSetHitToBlackboard(file, md5Hash, hashSetName, comment, db.getSendIngestMessages()); + try { + if (!org.sleuthkit.datamodel.Blackboard.checkIfArtifactExists(file, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT, attributeMap)) { + postHashSetHitToBlackboard(file, md5Hash, hashSetName, comment, db.getSendIngestMessages()); + } + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format( + "A problem occurred while checking for existing artifacts for file '%s' (id=%d).", name, fileId), ex); //NON-NLS + services.postMessage(IngestMessage.createErrorMessage( + HashLookupModuleFactory.getModuleName(), + Bundle.HashDbIngestModule_dialogTitle_errorFindingArtifacts(name), + Bundle.HashDbIngestModule_errorMessage_lookingForFileArtifacts(name))); + ret = ProcessResult.ERROR; } } long delta = (System.currentTimeMillis() - lookupstart); totals.totalLookuptime.addAndGet(delta); - } catch (BlackboardException ex) { - logger.log(Level.SEVERE, String.format( - "A problem occurred while checking for existing artifacts for file '%s' (id=%d).", name, fileId), ex); //NON-NLS - services.postMessage(IngestMessage.createErrorMessage( - HashLookupModuleFactory.getModuleName(), - Bundle.HashDbIngestModule_dialogTitle_errorFindingArtifacts(name), - Bundle.HashDbIngestModule_errorMessage_lookingForFileArtifacts(name))); - ret = ProcessResult.ERROR; } catch (TskException ex) { logger.log(Level.WARNING, String.format( "Couldn't lookup notable hash for file '%s' (id=%d) - see sleuthkit log for details", name, fileId), ex); //NON-NLS From 821b8ce04e4d269514e7519f73675ae0bcda9337 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Thu, 26 Jul 2018 14:36:36 -0400 Subject: [PATCH 047/105] Using new method signature. --- .../autopsy/modules/hashdatabase/HashDbIngestModule.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java index 66ecf89aea..e018a612e1 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java @@ -272,10 +272,10 @@ public class HashDbIngestModule implements FileIngestModule { * We have a match. Now create an artifact if it is * determined that one hasn't been created yet. */ - Map attributeMap = new HashMap<>(); - attributeMap.put(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SET_NAME), hashSetName); + List attributesList = new ArrayList<>(); + attributesList.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, HashLookupModuleFactory.getModuleName(), hashSetName)); try { - if (!org.sleuthkit.datamodel.Blackboard.checkIfArtifactExists(file, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT, attributeMap)) { + if (!org.sleuthkit.datamodel.Blackboard.artifactExists(file, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT, attributesList)) { postHashSetHitToBlackboard(file, md5Hash, hashSetName, comment, db.getSendIngestMessages()); } } catch (TskCoreException ex) { From 821eff842d91b538e291705933e83c24f60ed78a Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 26 Jul 2018 15:15:43 -0400 Subject: [PATCH 048/105] Make new public AbstractAbstractFileNode protected --- .../autopsy/commonfilesearch/FileInstanceNode.java | 2 +- .../datamodel/AbstractAbstractFileNode.java | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/commonfilesearch/FileInstanceNode.java b/Core/src/org/sleuthkit/autopsy/commonfilesearch/FileInstanceNode.java index 07c87035e1..899aa5abbc 100644 --- a/Core/src/org/sleuthkit/autopsy/commonfilesearch/FileInstanceNode.java +++ b/Core/src/org/sleuthkit/autopsy/commonfilesearch/FileInstanceNode.java @@ -77,7 +77,7 @@ public class FileInstanceNode extends FileNode { sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), NO_DESCR, this.getContent().getName())); sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), NO_DESCR, this.getContent().getParentPath())); - sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), NO_DESCR, getHashSetHitsForFile(this.getContent()))); + sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), NO_DESCR, getHashSetHitsCsvList(this.getContent()))); sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), NO_DESCR, this.getDataSource())); sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), NO_DESCR, StringUtils.defaultString(this.getContent().getMIMEType()))); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java index 28329f17c5..1a52a61bb2 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java @@ -251,7 +251,7 @@ public abstract class AbstractAbstractFileNode extends A map.put(TYPE_DIR.toString(), content.getDirType().getLabel()); map.put(TYPE_META.toString(), content.getMetaType().toString()); map.put(KNOWN.toString(), content.getKnown().getName()); - map.put(HASHSETS.toString(), getHashSetHitsForFile(content)); + map.put(HASHSETS.toString(), getHashSetHitsCsvList(content)); map.put(MD5HASH.toString(), StringUtils.defaultString(content.getMd5Hash())); map.put(ObjectID.toString(), content.getId()); map.put(MIMETYPE.toString(), StringUtils.defaultString(content.getMIMEType())); @@ -263,7 +263,7 @@ public abstract class AbstractAbstractFileNode extends A * to their sheets. * * @param sheetSet the modifiable Sheet.Set returned by - * Sheet.get(Sheet.PROPERTIES) + * Sheet.get(Sheet.PROPERTIES) */ @NbBundle.Messages("AbstractAbstractFileNode.tagsProperty.displayName=Tags") protected void addTagProperty(Sheet.Set sheetSet) { @@ -301,7 +301,15 @@ public abstract class AbstractAbstractFileNode extends A } } - public static String getHashSetHitsForFile(AbstractFile file) { + /** + * Gets a comma-separated values list of the names of the hash sets + * currently identified as including a given file. + * + * @param file The file. + * + * @return The CSV list of hash set names. + */ + protected static String getHashSetHitsCsvList(AbstractFile file) { try { return StringUtils.join(file.getHashSetNames(), ", "); } catch (TskCoreException tskCoreException) { From 4ad2b2c8fb425fb780cdc6cf84dba0812dd850c8 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Thu, 26 Jul 2018 17:22:15 -0400 Subject: [PATCH 049/105] Cleanup. --- .../modules/hashdatabase/Bundle.properties | 2 ++ .../modules/hashdatabase/Bundle_ja.properties | 22 +++++++++++++++++++ .../hashdatabase/HashDbIngestModule.java | 6 ++--- .../hashdatabase/HashLookupModuleFactory.java | 6 +++-- 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties index 3ca6c162b6..c18245d7c7 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties @@ -148,6 +148,8 @@ AddContentToHashDbAction.addFilesToHashSet.files=files AddContentToHashDbAction.addFilesToHashSet.file=file HashDbManager.errCreatingIndex.title=Error creating index HashDbManager.errCreatingIndex.msg=Error creating index\: {0} +HashLookupModuleFactory.getIngestJobSettingsPanel.exception.msg=Expected settings argument to be instanceof HashLookupModuleSettings +HashLookupModuleFactory.createFileIngestModule.exception.msg=Expected settings argument to be instanceof HashLookupModuleSettings HashLookupModuleSettingsPanel.alwaysCalcHashesCheckbox.toolTipText=Calculate MD5 even if no hash set is selected HashDbSearchPanel.hashTable.defaultModel.title.text=MD5 Hashes AddHashValuesToDatabaseDialog.JDialog.Title=Add Hashes to Hash Set diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties index 3d2ab7a085..d3ffff1cfb 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties @@ -76,7 +76,27 @@ HashDbImportDatabaseDialog.importHashDbErr=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\ HashDbImportDatabaseDialog.mustSelectHashDbFilePathMsg=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u30d5\u30a1\u30a4\u30eb\u30d1\u30b9\u306e\u9078\u629e\u304c\u5fc5\u8981\u3067\u3059\u3002 HashDbImportDatabaseDialog.hashDbDoesNotExistMsg=\u9078\u629e\u3055\u308c\u305f\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306f\u5b58\u5728\u3057\u307e\u305b\u3093\u3002 HashDbImportDatabaseDialog.errorMessage.failedToOpenHashDbMsg={0}\u3067\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u958b\u304f\u306e\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 +HashLookupModuleFactory.moduleName.text=\u30cf\u30c3\u30b7\u30e5\u30eb\u30c3\u30af\u30a2\u30c3\u30d7 +HashLookupModuleFactory.moduleDescription.text=\u6a19\u6e96\u306eNSRL\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306a\u3069\u3001\u63d0\u4f9b\u3055\u308c\u305f\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u5229\u7528\u3057\u3066\u3001\u65e2\u77e5\u307e\u305f\u306f\u7591\u308f\u3057\u3044\u3082\u306e\u3092\u691c\u77e5\u3057\u307e\u3059\u3002 +HashDbIngestModule.noKnownHashDbSetMsg=\u65e2\u77e5\u306e\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u5b58\u5728\u3057\u307e\u305b\u3093\u3002 +HashDbIngestModule.knownFileSearchWillNotExecuteWarn=\u65e2\u77e5\u306e\u30d5\u30a1\u30a4\u30eb\u691c\u7d22\u304c\u5b9f\u884c\u3055\u308c\u307e\u305b\u3093\u3002 +HashDbIngestModule.noKnownBadHashDbSetMsg=\u65e2\u77e5\u306e\u60aa\u8cea\u306a\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30bb\u30c3\u30c8\u306f\u3042\u308a\u307e\u305b\u3093\u3002 HashDbConfigPanel.dbNotIndexedMsg=\u6b21\u306e\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306f\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5316\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5316\u3057\u307e\u3059\u304b\uff1f\n{0} +HashDbIngestModule.knownBadFileSearchWillNotExecuteWarn=\u65e2\u77e5\u306e\u60aa\u8cea\u30d5\u30a1\u30a4\u30eb\u691c\u7d22\u306f\u5b9f\u884c\u3055\u308c\u307e\u305b\u3093\u3002 +HashDbIngestModule.fileReadErrorMsg=\u8aad\u307f\u8fbc\u307f\u30a8\u30e9\u30fc\uff1a {0} +HashDbIngestModule.calcHashValueErr={0}\u306e\u30cf\u30c3\u30b7\u30e5\u5024\u3092\u8a08\u7b97\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 +HashDbIngestModule.hashLookupErrorMsg=\u30cf\u30c3\u30b7\u30e5\u30eb\u30c3\u30af\u30a2\u30c3\u30d7\u30a8\u30e9\u30fc\uff1a {0} +HashDbIngestModule.lookingUpKnownBadHashValueErr={0}\u306e\u65e2\u77e5\u306e\u60aa\u8cea\u30cf\u30c3\u30b7\u30e5\u5024\u3092\u30eb\u30c3\u30af\u30a2\u30c3\u30d7\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 +HashDbIngestModule.lookingUpKnownHashValueErr={0}\u306e\u65e2\u77e5\u306e\u30cf\u30c3\u30b7\u30e5\u5024\u3092\u30eb\u30c3\u30af\u30a2\u30c3\u30d7\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 +HashDbIngestModule.postToBB.fileName=\u30d5\u30a1\u30a4\u30eb\u540d +HashDbIngestModule.postToBB.md5Hash=MD5\u30cf\u30c3\u30b7\u30e5 +HashDbIngestModule.postToBB.hashsetName=\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u540d +HashDbIngestModule.postToBB.knownBadMsg=\u65e2\u77e5\u306e\u60aa\u8cea\: {0} +HashDbIngestModule.complete.knownBadsFound=\u767a\u898b\u3055\u308c\u305f\u65e2\u77e5\u306e\u60aa\u8cea\uff1a +HashDbIngestModule.complete.totalCalcTime=\u8a08\u7b97\u6642\u9593\u306e\u5408\u8a08 +HashDbIngestModule.complete.totalLookupTime=\u30eb\u30c3\u30af\u30a2\u30c3\u30d7\u6642\u9593\u306e\u5408\u8a08 +HashDbIngestModule.complete.databasesUsed=\u5229\u7528\u3057\u305f\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\uff1a +HashDbIngestModule.complete.hashLookupResults=\u30cf\u30c3\u30b7\u30e5\u30eb\u30c3\u30af\u30a2\u30c3\u30d7\u7d50\u679c HashDbManager.moduleErrorListeningToUpdatesMsg=HashDbManager\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u3092\u78ba\u8a8d\u4e2d\u306b\u30e2\u30b8\u30e5\u30fc\u30eb\u304c\u30a8\u30e9\u30fc\u3092\u8d77\u3053\u3057\u307e\u3057\u305f\u3002\u3069\u306e\u30e2\u30b8\u30e5\u30fc\u30eb\u304c\u539f\u56e0\u306a\u306e\u304b\u3092\u30ed\u30b0\u3092\u78ba\u8a8d\u3057\u3066\u4e0b\u3055\u3044\u3002\u4e00\u90e8\u306e\u30c7\u30fc\u30bf\u304c\u5b8c\u5168\u3067\u306a\u3044\u3053\u3068\u304c\u3042\u308a\u307e\u3059\u3002 HashDbManager.replacingDuplicateHashsetNameMsg=\u91cd\u8907\u306e\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u540d {0} \u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f\u3002\n {1}\u306b\u66f8\u304d\u63db\u3048\u307e\u3059\u3002 HashDbManager.openHashDbErr=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u958b\u304f\u30a8\u30e9\u30fc @@ -142,6 +162,8 @@ HashLookupSettingsPanel.jLabel2.text=\u540d\u524d\uff1a HashLookupModuleSettingsPanel.alwaysCalcHashesCheckbox.text=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u306a\u304f\u3066\u3082\u3001MD5\u3092\u8a08\u7b97 HashLookupModuleSettingsPanel.knownHashDbsLabel.text=\u5229\u7528\u3059\u308b\u65e2\u77e5\u306e\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u9078\u629e\uff1a HashLookupModuleSettingsPanel.knownBadHashDbsLabel.text=\u51e6\u7406\u306b\u5229\u7528\u3059\u308b\u65e2\u77e5\u306e\u60aa\u8cea\u306a\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u9078\u629e\uff1a +HashLookupModuleFactory.createFileIngestModule.exception.msg=\u8a2d\u5b9a\u3092\u884c\u3046\u70ba\u306e\u60f3\u5b9a\u3055\u308c\u308b\u5f15\u6570\u306finstanceof HashLookupModuleSettings\u3067\u3059\u3002 +HashLookupModuleFactory.getIngestJobSettingsPanel.exception.msg=\u8a2d\u5b9a\u3092\u884c\u3046\u70ba\u306e\u60f3\u5b9a\u3055\u308c\u308b\u5f15\u6570\u306finstanceof HashLookupModuleSettings\u3067\u3059\u3002 HashLookupModuleSettingsPanel.alwaysCalcHashesCheckbox.toolTipText=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u306a\u304f\u3066\u3082\u3001MD5\u3092\u8a08\u7b97 HashDbSearchPanel.hashTable.defaultModel.title.text=MD5\u30cf\u30c3\u30b7\u30e5 AddContentToHashDbAction.addFilesToHashSet.unableToAddFileEmptyMsg=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306b{0}\u3092\u8ffd\u52a0\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30d5\u30a1\u30a4\u30eb\u306b\u30b3\u30f3\u30c6\u30f3\u30c4\u304c\u3042\u308a\u307e\u305b\u3093\u3002 diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java index e018a612e1..3067acff4a 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java @@ -24,7 +24,6 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.concurrent.atomic.AtomicLong; import java.util.logging.Level; import org.openide.util.NbBundle.Messages; @@ -275,10 +274,11 @@ public class HashDbIngestModule implements FileIngestModule { List attributesList = new ArrayList<>(); attributesList.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, HashLookupModuleFactory.getModuleName(), hashSetName)); try { - if (!org.sleuthkit.datamodel.Blackboard.artifactExists(file, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT, attributesList)) { + org.sleuthkit.datamodel.Blackboard tskBlackboard = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard(); + if (tskBlackboard.artifactExists(file, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT, attributesList) == false) { postHashSetHitToBlackboard(file, md5Hash, hashSetName, comment, db.getSendIngestMessages()); } - } catch (TskCoreException ex) { + } catch (NoCurrentCaseException | TskCoreException ex) { logger.log(Level.SEVERE, String.format( "A problem occurred while checking for existing artifacts for file '%s' (id=%d).", name, fileId), ex); //NON-NLS services.postMessage(IngestMessage.createErrorMessage( diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java index a327a659af..51995505c5 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java @@ -78,7 +78,8 @@ public class HashLookupModuleFactory extends IngestModuleFactoryAdapter { @Override public IngestModuleIngestJobSettingsPanel getIngestJobSettingsPanel(IngestModuleIngestJobSettings settings) { if (!(settings instanceof HashLookupModuleSettings)) { - throw new IllegalArgumentException("Expected settings argument to be an instance of HashLookupModuleSettings."); + throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(), + "HashLookupModuleFactory.getIngestJobSettingsPanel.exception.msg")); } if (moduleSettingsPanel == null) { moduleSettingsPanel = new HashLookupModuleSettingsPanel((HashLookupModuleSettings) settings); @@ -108,7 +109,8 @@ public class HashLookupModuleFactory extends IngestModuleFactoryAdapter { @Override public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings settings) { if (!(settings instanceof HashLookupModuleSettings)) { - throw new IllegalArgumentException("Expected settings argument to be an instance of HashLookupModuleSettings."); + throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(), + "HashLookupModuleFactory.getIngestJobSettingsPanel.exception.msg")); } return new HashDbIngestModule((HashLookupModuleSettings) settings); } From 5f43a4fe52d76c0aa16d2c4f64bce2d9d040d0b1 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Thu, 26 Jul 2018 22:22:02 -0400 Subject: [PATCH 050/105] Reverted comments back to 'Bundle.properties'. --- .../modules/hashdatabase/Bundle.properties | 17 +++++ .../hashdatabase/HashDbIngestModule.java | 69 +++++++------------ .../hashdatabase/HashLookupModuleFactory.java | 8 +-- 3 files changed, 43 insertions(+), 51 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties index c18245d7c7..a3f75b9048 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties @@ -87,6 +87,23 @@ HashDbImportDatabaseDialog.importHashDbErr=Import Hash Set Error HashDbImportDatabaseDialog.mustSelectHashDbFilePathMsg=A hash set file path must be selected. HashDbImportDatabaseDialog.hashDbDoesNotExistMsg=The selected hash set does not exist. HashDbImportDatabaseDialog.errorMessage.failedToOpenHashDbMsg=Failed to open hash set at {0}. +HashLookupModuleFactory.moduleName.text=Hash Lookup +HashLookupModuleFactory.moduleDescription.text=Identifies known and notable files using supplied hash sets, such as a standard NSRL hash set. +HashDbIngestModule.fileReadErrorMsg=Read Error\: {0} +HashDbIngestModule.calcHashValueErr=Error encountered while calculating the hash value for {0}. +HashDbIngestModule.hashLookupErrorMsg=Hash Lookup Error\: {0} +HashDbIngestModule.settingKnownBadStateErr=Error encountered while setting notable state for {0}. +HashDbIngestModule.lookingUpKnownBadHashValueErr=Error encountered while looking up notable hash value for {0}. +HashDbIngestModule.lookingUpKnownHashValueErr=Error encountered while looking up known hash value for {0}. +HashDbIngestModule.postToBB.fileName=File Name +HashDbIngestModule.postToBB.md5Hash=MD5 Hash +HashDbIngestModule.postToBB.hashsetName=Hash Set Name +HashDbIngestModule.postToBB.knownBadMsg=Notable\: {0} +HashDbIngestModule.complete.knownBadsFound=Notables found\: +HashDbIngestModule.complete.totalCalcTime=Total Calculation Time +HashDbIngestModule.complete.totalLookupTime=Total Lookup Time +HashDbIngestModule.complete.databasesUsed=Hash Sets Used\: +HashDbIngestModule.complete.hashLookupResults=Hash Lookup Results HashDbManager.moduleErrorListeningToUpdatesMsg=A module caused an error listening to HashDbManager updates. See log to determine which module. Some data could be incomplete. HashDbManager.replacingDuplicateHashsetNameMsg=Duplicate hash set name {0} found.\nReplacing with {1}. HashDbManager.openHashDbErr=Open Hash Set Error diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java index 3067acff4a..46165e34fa 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java @@ -26,6 +26,7 @@ import java.util.HashMap; 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.NoCurrentCaseException; @@ -54,6 +55,12 @@ import org.sleuthkit.datamodel.TskException; /** * File ingest module to mark files based on hash values. */ +@Messages({ + "HashDbIngestModule.noKnownBadHashDbSetMsg=No notable hash set.", + "HashDbIngestModule.knownBadFileSearchWillNotExecuteWarn=Notable file search will not be executed.", + "HashDbIngestModule.noKnownHashDbSetMsg=No known hash set.", + "HashDbIngestModule.knownFileSearchWillNotExecuteWarn=Known file search will not be executed." +}) public class HashDbIngestModule implements FileIngestModule { private static final Logger logger = Logger.getLogger(HashDbIngestModule.class.getName()); @@ -98,12 +105,6 @@ public class HashDbIngestModule implements FileIngestModule { this.settings = settings; } - @Messages({ - "HashDbIngestModule.noKnownBadHashDbSetMsg=No notable hash set.", - "HashDbIngestModule.knownBadFileSearchWillNotExecuteWarn=Notable file search will not be executed.", - "HashDbIngestModule.noKnownHashDbSetMsg=No known hash set.", - "HashDbIngestModule.knownFileSearchWillNotExecuteWarn=Known file search will not be executed." - }) @Override public void startUp(org.sleuthkit.autopsy.ingest.IngestJobContext context) throws IngestModuleException { jobId = context.getJobId(); @@ -121,7 +122,7 @@ public class HashDbIngestModule implements FileIngestModule { if (knownBadHashSets.isEmpty()) { services.postMessage(IngestMessage.createWarningMessage( HashLookupModuleFactory.getModuleName(), - Bundle.HashDbIngestModule_noKnownBadHashDbSetMsg(), + NbBundle.getMessage(this.getClass(), "HashDbIngestModule.noKnownBadHashDbSetMsg"), Bundle.HashDbIngestModule_knownBadFileSearchWillNotExecuteWarn())); } @@ -156,16 +157,6 @@ public class HashDbIngestModule implements FileIngestModule { } @Messages({ - "# {0} - File name", - "HashDbIngestModule.fileReadErrorMsg=Read Error: {0}", - "# {0} - File name", - "HashDbIngestModule.calcHashValueErr=Error encountered while calculating the hash value for {0}.", - "# {0} - File name", - "HashDbIngestModule.hashLookupErrorMsg=Hash Lookup Error: {0}", - "# {0} - File name", - "HashDbIngestModule.lookingUpKnownBadHashValueErr=Error encountered while looking up notable hash value for {0}.", - "# {0} - File name", - "HashDbIngestModule.lookingUpKnownHashValueErr=Error encountered while looking up known hash value for {0}.", "# {0} - File name", "HashDbIngestModule.dialogTitle.errorFindingArtifacts=Error Finding Artifacts: {0}", "# {0} - File name", @@ -232,8 +223,8 @@ public class HashDbIngestModule implements FileIngestModule { logger.log(Level.WARNING, String.format("Error calculating hash of file '%s' (id=%d).", name, fileId), ex); //NON-NLS services.postMessage(IngestMessage.createErrorMessage( HashLookupModuleFactory.getModuleName(), - Bundle.HashDbIngestModule_fileReadErrorMsg(name), - Bundle.HashDbIngestModule_calcHashValueErr(name))); + NbBundle.getMessage(this.getClass(), "HashDbIngestModule.fileReadErrorMsg", name), + NbBundle.getMessage(this.getClass(), "HashDbIngestModule.calcHashValueErr", name))); return ProcessResult.ERROR; } } @@ -296,8 +287,8 @@ public class HashDbIngestModule implements FileIngestModule { "Couldn't lookup notable hash for file '%s' (id=%d) - see sleuthkit log for details", name, fileId), ex); //NON-NLS services.postMessage(IngestMessage.createErrorMessage( HashLookupModuleFactory.getModuleName(), - Bundle.HashDbIngestModule_hashLookupErrorMsg(name), - Bundle.HashDbIngestModule_lookingUpKnownBadHashValueErr(name))); + NbBundle.getMessage(this.getClass(), "HashDbIngestModule.hashLookupErrorMsg", name), + NbBundle.getMessage(this.getClass(), "HashDbIngestModule.lookingUpKnownBadHashValueErr", name))); ret = ProcessResult.ERROR; } } @@ -321,8 +312,8 @@ public class HashDbIngestModule implements FileIngestModule { "Couldn't lookup known hash for file '%s' (id=%d) - see sleuthkit log for details", name, fileId), ex); //NON-NLS services.postMessage(IngestMessage.createErrorMessage( HashLookupModuleFactory.getModuleName(), - Bundle.HashDbIngestModule_hashLookupErrorMsg(name), - Bundle.HashDbIngestModule_lookingUpKnownHashValueErr(name))); + NbBundle.getMessage(this.getClass(), "HashDbIngestModule.hashLookupErrorMsg", name), + NbBundle.getMessage(this.getClass(), "HashDbIngestModule.lookingUpKnownHashValueErr", name))); ret = ProcessResult.ERROR; } } @@ -342,12 +333,7 @@ public class HashDbIngestModule implements FileIngestModule { * @param showInboxMessage Show a message in the inbox? */ @Messages({ - "HashDbIngestModule.indexError.message=Failed to index hashset hit artifact for keyword search.", - "HashDbIngestModule.postToBB.fileName=File Name", - "HashDbIngestModule.postToBB.md5Hash=MD5 Hash", - "HashDbIngestModule.postToBB.hashsetName=Hash Set Name", - "# {0} - File name", - "HashDbIngestModule.postToBB.knownBadMsg=Notable: {0}" + "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 { @@ -378,7 +364,7 @@ public class HashDbIngestModule implements FileIngestModule { //hit detailsSb.append(""); //NON-NLS detailsSb.append("") //NON-NLS - .append(Bundle.HashDbIngestModule_postToBB_fileName()) + .append(NbBundle.getMessage(this.getClass(), "HashDbIngestModule.postToBB.fileName")) .append(""); //NON-NLS detailsSb.append("") //NON-NLS .append(abstractFile.getName()) @@ -387,14 +373,14 @@ public class HashDbIngestModule implements FileIngestModule { detailsSb.append(""); //NON-NLS detailsSb.append("") //NON-NLS - .append(Bundle.HashDbIngestModule_postToBB_md5Hash()) + .append(NbBundle.getMessage(this.getClass(), "HashDbIngestModule.postToBB.md5Hash")) .append(""); //NON-NLS detailsSb.append("").append(md5Hash).append(""); //NON-NLS detailsSb.append(""); //NON-NLS detailsSb.append(""); //NON-NLS detailsSb.append("") //NON-NLS - .append(Bundle.HashDbIngestModule_postToBB_hashsetName()) + .append(NbBundle.getMessage(this.getClass(), "HashDbIngestModule.postToBB.hashsetName")) .append(""); //NON-NLS detailsSb.append("").append(hashSetName).append(""); //NON-NLS detailsSb.append(""); //NON-NLS @@ -402,7 +388,7 @@ public class HashDbIngestModule implements FileIngestModule { detailsSb.append(""); //NON-NLS services.postMessage(IngestMessage.createDataMessage(HashLookupModuleFactory.getModuleName(), - Bundle.HashDbIngestModule_postToBB_knownBadMsg(abstractFile.getName()), + NbBundle.getMessage(this.getClass(), "HashDbIngestModule.postToBB.knownBadMsg", abstractFile.getName()), detailsSb.toString(), abstractFile.getName() + md5Hash, badFile)); @@ -420,13 +406,6 @@ public class HashDbIngestModule implements FileIngestModule { * @param knownBadHashSets The list of hash sets for "known bad" files. * @param knownHashSets The list of hash sets for "known" files. */ - @Messages({ - "HashDbIngestModule.complete.knownBadsFound=Notables found:", - "HashDbIngestModule.complete.totalCalcTime=Total Calculation Time", - "HashDbIngestModule.complete.totalLookupTime=Total Lookup Time", - "HashDbIngestModule.complete.databasesUsed=Hash Sets Used:", - "HashDbIngestModule.complete.hashLookupResults=Hash Lookup Results" - }) private static synchronized void postSummary(long jobId, List knownBadHashSets, List knownHashSets) { IngestJobTotals jobTotals = getTotalsForIngestJobs(jobId); @@ -438,20 +417,20 @@ public class HashDbIngestModule implements FileIngestModule { detailsSb.append(""); //NON-NLS detailsSb.append(""); //NON-NLS detailsSb.append(""); //NON-NLS detailsSb.append("\n"); //NON-NLS detailsSb.append("\n"); //NON-NLS detailsSb.append("
    ") //NON-NLS - .append(Bundle.HashDbIngestModule_complete_knownBadsFound()) + .append(NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.complete.knownBadsFound")) .append("").append(jobTotals.totalKnownBadCount.get()).append("
    ") //NON-NLS - .append(Bundle.HashDbIngestModule_complete_totalCalcTime()) + .append(NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.complete.totalCalcTime")) .append("").append(jobTotals.totalCalctime.get()).append("
    ") //NON-NLS - .append(Bundle.HashDbIngestModule_complete_totalLookupTime()) + .append(NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.complete.totalLookupTime")) .append("").append(jobTotals.totalLookuptime.get()).append("
    "); //NON-NLS detailsSb.append("

    ") //NON-NLS - .append(Bundle.HashDbIngestModule_complete_databasesUsed()) + .append(NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.complete.databasesUsed")) .append("

    \n
      "); //NON-NLS for (HashDb db : knownBadHashSets) { detailsSb.append("
    • ").append(db.getHashSetName()).append("
    • \n"); //NON-NLS @@ -462,7 +441,7 @@ public class HashDbIngestModule implements FileIngestModule { IngestServices.getInstance().postMessage(IngestMessage.createMessage( IngestMessage.MessageType.INFO, HashLookupModuleFactory.getModuleName(), - Bundle.HashDbIngestModule_complete_hashLookupResults(), + NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.complete.hashLookupResults"), detailsSb.toString())); } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java index 51995505c5..fc9ab24521 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java @@ -32,10 +32,6 @@ import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel; * A factory that creates file ingest modules that do hash database lookups. */ @ServiceProvider(service = IngestModuleFactory.class) -@NbBundle.Messages({ - "HashLookupModuleFactory.moduleName.text=Hash Lookup", - "HashLookupModuleFactory.moduleDescription.text=Identifies known and notable files using supplied hash sets, such as a standard NSRL hash set." -}) public class HashLookupModuleFactory extends IngestModuleFactoryAdapter { private HashLookupModuleSettingsPanel moduleSettingsPanel = null; @@ -51,12 +47,12 @@ public class HashLookupModuleFactory extends IngestModuleFactoryAdapter { * @return The module name. */ static String getModuleName() { - return Bundle.HashLookupModuleFactory_moduleName_text(); + return NbBundle.getMessage(HashLookupModuleFactory.class, "HashLookupModuleFactory.moduleName.text"); } @Override public String getModuleDescription() { - return Bundle.HashLookupModuleFactory_moduleDescription_text(); + return NbBundle.getMessage(HashLookupModuleFactory.class, "HashLookupModuleFactory.moduleDescription.text"); } @Override From dfd97722f9e1d5d7d90b74c32a3d3401c2fc35b9 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Thu, 26 Jul 2018 23:08:46 -0400 Subject: [PATCH 051/105] Put SleuthkitCase object back in constructor. --- .../modules/hashdatabase/HashDbIngestModule.java | 13 +++++++++---- .../hashdatabase/HashLookupModuleFactory.java | 7 ++++++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java index 46165e34fa..ee3ba1c089 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java @@ -48,6 +48,7 @@ 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; @@ -66,6 +67,7 @@ public class HashDbIngestModule implements FileIngestModule { private static final Logger logger = Logger.getLogger(HashDbIngestModule.class.getName()); private static final int MAX_COMMENT_SIZE = 500; private final IngestServices services = IngestServices.getInstance(); + private final SleuthkitCase skCase; private final HashDbManager hashDbManager = HashDbManager.getInstance(); private final HashLookupModuleSettings settings; private final List knownBadHashSets = new ArrayList<>(); @@ -100,9 +102,12 @@ public class HashDbIngestModule implements FileIngestModule { * object is used to configure the module. * * @param settings The module settings. + * + * @throws NoCurrentCaseException If there is no open case. */ - HashDbIngestModule(HashLookupModuleSettings settings) { + HashDbIngestModule(HashLookupModuleSettings settings) throws NoCurrentCaseException { this.settings = settings; + skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); } @Override @@ -122,7 +127,7 @@ public class HashDbIngestModule implements FileIngestModule { if (knownBadHashSets.isEmpty()) { services.postMessage(IngestMessage.createWarningMessage( HashLookupModuleFactory.getModuleName(), - NbBundle.getMessage(this.getClass(), "HashDbIngestModule.noKnownBadHashDbSetMsg"), + Bundle.HashDbIngestModule_noKnownBadHashDbSetMsg(), Bundle.HashDbIngestModule_knownBadFileSearchWillNotExecuteWarn())); } @@ -265,11 +270,11 @@ public class HashDbIngestModule implements FileIngestModule { List attributesList = new ArrayList<>(); attributesList.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, HashLookupModuleFactory.getModuleName(), hashSetName)); try { - org.sleuthkit.datamodel.Blackboard tskBlackboard = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard(); + org.sleuthkit.datamodel.Blackboard tskBlackboard = skCase.getBlackboard(); if (tskBlackboard.artifactExists(file, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT, attributesList) == false) { postHashSetHitToBlackboard(file, md5Hash, hashSetName, comment, db.getSendIngestMessages()); } - } catch (NoCurrentCaseException | TskCoreException ex) { + } catch (TskCoreException ex) { logger.log(Level.SEVERE, String.format( "A problem occurred while checking for existing artifacts for file '%s' (id=%d).", name, fileId), ex); //NON-NLS services.postMessage(IngestMessage.createErrorMessage( diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java index fc9ab24521..2a20eb8900 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.modules.hashdatabase; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Version; import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter; import org.sleuthkit.autopsy.ingest.FileIngestModule; @@ -108,6 +109,10 @@ public class HashLookupModuleFactory extends IngestModuleFactoryAdapter { throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(), "HashLookupModuleFactory.getIngestJobSettingsPanel.exception.msg")); } - return new HashDbIngestModule((HashLookupModuleSettings) settings); + try { + return new HashDbIngestModule((HashLookupModuleSettings) settings); + } catch (NoCurrentCaseException ex) { + throw new IllegalArgumentException("Exception while getting open case.", ex); + } } } From d01f254d6bd58ce27aefa2e978f25405b9918dc6 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Thu, 26 Jul 2018 23:16:30 -0400 Subject: [PATCH 052/105] Typo fixed. --- .../autopsy/modules/hashdatabase/HashLookupModuleFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java index 2a20eb8900..af27157fd8 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java @@ -107,7 +107,7 @@ public class HashLookupModuleFactory extends IngestModuleFactoryAdapter { public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings settings) { if (!(settings instanceof HashLookupModuleSettings)) { throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(), - "HashLookupModuleFactory.getIngestJobSettingsPanel.exception.msg")); + "HashLookupModuleFactory.createFileIngestModule.exception.msg")); } try { return new HashDbIngestModule((HashLookupModuleSettings) settings); From b9dc69ad455ccda0c34ebc47b7122a17971f20d1 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Fri, 27 Jul 2018 11:55:24 -0400 Subject: [PATCH 053/105] Updated the regex in FileUtil.escapeFileName function to remove ascii control characters --- Core/src/org/sleuthkit/autopsy/coreutils/FileUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/FileUtil.java b/Core/src/org/sleuthkit/autopsy/coreutils/FileUtil.java index 4c742acfac..5b432124ba 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/FileUtil.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/FileUtil.java @@ -169,7 +169,7 @@ public class FileUtil { public static String escapeFileName(String fileName) { //for now escaping /:"*?<>| (not valid in file name, at least on Windows) //with underscores. We are only keeping \ as it could be part of the path. - return fileName.replaceAll("[/:\"*?<>|]+", "_"); + return fileName.replaceAll("[\\p{Cntrl}/:\"*?<>|]+", "_"); } /** From 42835825a9533da9ead8ecf85ca04db981e76b4b Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 27 Jul 2018 18:06:12 -0400 Subject: [PATCH 054/105] AutopsyTreeChildrenFactory => final AutopsyTreeChildFactory --- ...ildrenFactory.java => AutopsyTreeChildFactory.java} | 4 ++-- .../directorytree/DirectoryTreeTopComponent.java | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) rename Core/src/org/sleuthkit/autopsy/datamodel/{AutopsyTreeChildrenFactory.java => AutopsyTreeChildFactory.java} (97%) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildrenFactory.java b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java similarity index 97% rename from Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildrenFactory.java rename to Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java index 9573347eb9..70f0ca3ce6 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildrenFactory.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java @@ -41,9 +41,9 @@ import org.sleuthkit.datamodel.TskCoreException; * Child factory to create the top level children of the autopsy tree * */ -public class AutopsyTreeChildrenFactory extends ChildFactory.Detachable { +public final class AutopsyTreeChildFactory extends ChildFactory.Detachable { - private static final Logger logger = Logger.getLogger(AutopsyTreeChildrenFactory.class.getName()); + private static final Logger logger = Logger.getLogger(AutopsyTreeChildFactory.class.getName()); /** * Listener for handling DATA_SOURCE_ADDED events. diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index c84d0ee1f2..fb9ded33e2 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -80,7 +80,7 @@ import org.sleuthkit.autopsy.datamodel.FileTypesByMimeType; import org.sleuthkit.autopsy.datamodel.InterestingHits; import org.sleuthkit.autopsy.datamodel.KeywordHits; import org.sleuthkit.autopsy.datamodel.ResultsNode; -import org.sleuthkit.autopsy.datamodel.AutopsyTreeChildrenFactory; +import org.sleuthkit.autopsy.datamodel.AutopsyTreeChildFactory; import org.sleuthkit.autopsy.datamodel.ViewsNode; import org.sleuthkit.autopsy.datamodel.accounts.Accounts; import org.sleuthkit.autopsy.datamodel.accounts.BINRange; @@ -108,7 +108,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat private final LinkedList forwardList; private static final String PREFERRED_ID = "DirectoryTreeTopComponent"; //NON-NLS private static final Logger LOGGER = Logger.getLogger(DirectoryTreeTopComponent.class.getName()); - private AutopsyTreeChildrenFactory autopsyTreeChildrenFactory; + private AutopsyTreeChildFactory autopsyTreeChildFactory; private Children autopsyTreeChildren; private static final long DEFAULT_DATASOURCE_GROUPING_THRESHOLD = 5; // Threshold for prompting the user about grouping by data source private static final String GROUPING_THRESHOLD_NAME = "GroupDataSourceThreshold"; @@ -476,8 +476,8 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat } // if there's at least one image, load the image and open the top componen - autopsyTreeChildrenFactory = new AutopsyTreeChildrenFactory(); - autopsyTreeChildren = Children.create(autopsyTreeChildrenFactory, true); + autopsyTreeChildFactory = new AutopsyTreeChildFactory(); + autopsyTreeChildren = Children.create(autopsyTreeChildFactory, true); Node root = new AbstractNode(autopsyTreeChildren) { //JIRA-2807: What is the point of these overrides? /** @@ -909,7 +909,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat } // refresh all children of the root. - autopsyTreeChildrenFactory.refreshChildren(); + autopsyTreeChildFactory.refreshChildren(); // Select the first node and reset the selection history // This should happen on the EDT once the tree has been rebuilt. From 490d8df3e7fdfd5443a5bf19cceaeb9f3217ab90 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Mon, 30 Jul 2018 10:52:47 -0400 Subject: [PATCH 055/105] Preventing duplicate keyword hits. --- .../autopsy/keywordsearch/LuceneQuery.java | 63 +++++++++++------- .../autopsy/keywordsearch/QueryResults.java | 11 +++- .../autopsy/keywordsearch/RegexQuery.java | 66 +++++++++++-------- 3 files changed, 87 insertions(+), 53 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LuceneQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LuceneQuery.java index e13531da26..fadc2f5107 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LuceneQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LuceneQuery.java @@ -32,6 +32,8 @@ import org.apache.solr.client.solrj.response.QueryResponse; import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrDocumentList; import org.apache.solr.common.params.CursorMarkParams; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.EscapeUtil; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Version; @@ -40,6 +42,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskException; @@ -203,15 +206,44 @@ class LuceneQuery implements KeywordSearchQuery { * @param listName The name of the keyword list that contained the * keyword for which the hit was found. * - * - * @return The newly created artifact or null if there was a problem - * creating it. + * @return The newly created artifact, or null if one wasn't created due to + * either the artifact already existing or an error while trying to + * create it. */ @Override public BlackboardArtifact postKeywordHitToBlackboard(Content content, Keyword foundKeyword, KeywordHit hit, String snippet, String listName) { final String MODULE_NAME = KeywordSearchModuleFactory.getModuleName(); - Collection attributes = new ArrayList<>(); + List attributesList = new ArrayList<>(); + attributesList.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD, MODULE_NAME, foundKeyword.getSearchTerm())); + if (originalKeyword != null) { + BlackboardAttribute.ATTRIBUTE_TYPE selType = originalKeyword.getArtifactAttributeType(); + if (selType != null) { + attributesList.add(new BlackboardAttribute(selType, MODULE_NAME, foundKeyword.getSearchTerm())); + } + + if (originalKeyword.searchTermIsWholeWord()) { + attributesList.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE, MODULE_NAME, KeywordSearch.QueryType.LITERAL.ordinal())); + } else { + attributesList.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE, MODULE_NAME, KeywordSearch.QueryType.SUBSTRING.ordinal())); + } + } + if (StringUtils.isNotBlank(listName)) { + attributesList.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, listName)); + } + + try { + SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + org.sleuthkit.datamodel.Blackboard tskBlackboard = tskCase.getBlackboard(); + if (tskBlackboard.artifactExists(content, BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT, attributesList)) { + return null; + } + } catch (NoCurrentCaseException | TskCoreException ex) { + logger.log(Level.SEVERE, String.format( + "A problem occurred while checking for existing artifacts for file '%s' (id=%d).", + content.getName(), content.getId()), ex); //NON-NLS + } + BlackboardArtifact bba; try { bba = content.newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT); @@ -221,32 +253,15 @@ class LuceneQuery implements KeywordSearchQuery { } if (snippet != null) { - attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW, MODULE_NAME, snippet)); - } - attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD, MODULE_NAME, foundKeyword.getSearchTerm())); - if (StringUtils.isNotBlank(listName)) { - attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, listName)); - } - - if (originalKeyword != null) { - BlackboardAttribute.ATTRIBUTE_TYPE selType = originalKeyword.getArtifactAttributeType(); - if (selType != null) { - attributes.add(new BlackboardAttribute(selType, MODULE_NAME, foundKeyword.getSearchTerm())); - } - - if (originalKeyword.searchTermIsWholeWord()) { - attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE, MODULE_NAME, KeywordSearch.QueryType.LITERAL.ordinal())); - } else { - attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE, MODULE_NAME, KeywordSearch.QueryType.SUBSTRING.ordinal())); - } + attributesList.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW, MODULE_NAME, snippet)); } hit.getArtifactID().ifPresent(artifactID - -> attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, artifactID)) + -> attributesList.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, artifactID)) ); try { - bba.addAttributes(attributes); //write out to bb + bba.addAttributes(attributesList); //write out to bb return bba; } catch (TskCoreException e) { logger.log(Level.WARNING, "Error adding bb attributes to artifact", e); //NON-NLS diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryResults.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryResults.java index e27a01b063..3b7dd81fa0 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryResults.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryResults.java @@ -41,6 +41,7 @@ import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; +import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; @@ -65,7 +66,7 @@ class QueryResults { * and publishing an event to notify subscribers of the blackboard posts. * * The KeywordSearchQuery is used to do the blackboard posts. - * + * * @param query The query. */ QueryResults(KeywordSearchQuery query) { @@ -220,8 +221,14 @@ class QueryResults { } /* - * Post an artifact for the hit to the blackboard. + * Create an artifact if it is determined that one hasn't been + * created yet. */ + if (content == null) { + logger.log(Level.WARNING, "Cannot add artifact for keyword hit to blackboard without a Content object."); //NON-NLS + continue; // Cycle to the next KeywordHit. + } + BlackboardArtifact artifact = query.postKeywordHitToBlackboard(content, keyword, hit, snippet, query.getKeywordList().getName()); /* diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java index cb640e20bd..1706cdef60 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java @@ -55,6 +55,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; @@ -74,7 +75,7 @@ import org.sleuthkit.datamodel.TskData; */ final class RegexQuery implements KeywordSearchQuery { - public static final Logger LOGGER = Logger.getLogger(RegexQuery.class.getName()); + public static final Logger logger = Logger.getLogger(RegexQuery.class.getName()); /** * Lucene regular expressions do not support the following Java predefined @@ -213,7 +214,7 @@ final class RegexQuery implements KeywordSearchQuery { hitsForKeyword.add(hit); } } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Error creating keyword hits", ex); //NON-NLS + logger.log(Level.SEVERE, "Error creating keyword hits", ex); //NON-NLS } } @@ -223,7 +224,7 @@ final class RegexQuery implements KeywordSearchQuery { } cursorMark = nextCursorMark; } catch (KeywordSearchModuleException ex) { - LOGGER.log(Level.SEVERE, "Error executing Regex Solr Query: " + keywordString, ex); //NON-NLS + logger.log(Level.SEVERE, "Error executing Regex Solr Query: " + keywordString, ex); //NON-NLS MessageNotifyUtil.Notify.error(NbBundle.getMessage(Server.class, "Server.query.exception.msg", keywordString), ex.getCause().getMessage()); } } @@ -437,18 +438,38 @@ final class RegexQuery implements KeywordSearchQuery { * @param listName The name of the keyword list that contained the * keyword for which the hit was found. * - * - * @return The newly created artifact or null if there was a problem - * creating it. + * @return The newly created artifact, or null if one wasn't created due to + * either the artifact already existing or an error while trying to + * create it. */ @Override public BlackboardArtifact postKeywordHitToBlackboard(Content content, Keyword foundKeyword, KeywordHit hit, String snippet, String listName) { final String MODULE_NAME = KeywordSearchModuleFactory.getModuleName(); if (content == null) { - LOGGER.log(Level.WARNING, "Error adding artifact for keyword hit to blackboard"); //NON-NLS + logger.log(Level.WARNING, "Error adding artifact for keyword hit to blackboard"); //NON-NLS return null; } + + List attributesList = new ArrayList<>(); + attributesList.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD, MODULE_NAME, foundKeyword.getSearchTerm())); + attributesList.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE, MODULE_NAME, KeywordSearch.QueryType.REGEX.ordinal())); + attributesList.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP, MODULE_NAME, getQueryString())); + if (StringUtils.isNotBlank(listName)) { + attributesList.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, listName)); + } + + try { + SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + org.sleuthkit.datamodel.Blackboard tskBlackboard = tskCase.getBlackboard(); + if (tskBlackboard.artifactExists(content, BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT, attributesList)) { + return null; + } + } catch (NoCurrentCaseException | TskCoreException ex) { + logger.log(Level.SEVERE, String.format( + "A problem occurred while checking for existing artifacts for file '%s' (id=%d).", + content.getName(), content.getId()), ex); //NON-NLS + } /* * Credit Card number hits are handled differently @@ -463,36 +484,27 @@ final class RegexQuery implements KeywordSearchQuery { * regex attributes */ BlackboardArtifact newArtifact; - Collection attributes = new ArrayList<>(); - - attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD, MODULE_NAME, foundKeyword.getSearchTerm())); - attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP, MODULE_NAME, getQueryString())); try { newArtifact = content.newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT); } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Error adding artifact for keyword hit to blackboard", ex); //NON-NLS + logger.log(Level.SEVERE, "Error adding artifact for keyword hit to blackboard", ex); //NON-NLS return null; } - if (StringUtils.isNotBlank(listName)) { - attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, listName)); - } if (snippet != null) { - attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW, MODULE_NAME, snippet)); + attributesList.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW, MODULE_NAME, snippet)); } hit.getArtifactID().ifPresent(artifactID - -> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, artifactID)) + -> attributesList.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, artifactID)) ); - attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE, MODULE_NAME, KeywordSearch.QueryType.REGEX.ordinal())); - try { - newArtifact.addAttributes(attributes); + newArtifact.addAttributes(attributesList); return newArtifact; } catch (TskCoreException e) { - LOGGER.log(Level.SEVERE, "Error adding bb attributes for terms search artifact", e); //NON-NLS + logger.log(Level.SEVERE, "Error adding bb attributes for terms search artifact", e); //NON-NLS return null; } } @@ -502,7 +514,7 @@ final class RegexQuery implements KeywordSearchQuery { final String MODULE_NAME = KeywordSearchModuleFactory.getModuleName(); if (originalKeyword.getArtifactAttributeType() != ATTRIBUTE_TYPE.TSK_CARD_NUMBER) { - LOGGER.log(Level.SEVERE, "Keyword hit is not a credit card number"); //NON-NLS + logger.log(Level.SEVERE, "Keyword hit is not a credit card number"); //NON-NLS return; } /* @@ -525,13 +537,13 @@ final class RegexQuery implements KeywordSearchQuery { if (ccnAttribute == null || StringUtils.isBlank(ccnAttribute.getValueString())) { if (hit.isArtifactHit()) { - LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for artifact keyword hit: term = %s, snippet = '%s', artifact id = %d", foundKeyword.getSearchTerm(), hit.getSnippet(), hit.getArtifactID().get())); //NON-NLS + logger.log(Level.SEVERE, String.format("Failed to parse credit card account number for artifact keyword hit: term = %s, snippet = '%s', artifact id = %d", foundKeyword.getSearchTerm(), hit.getSnippet(), hit.getArtifactID().get())); //NON-NLS } else { try { - LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s', object id = %d", foundKeyword.getSearchTerm(), hit.getSnippet(), hit.getContentID())); //NON-NLS + logger.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s', object id = %d", foundKeyword.getSearchTerm(), hit.getSnippet(), hit.getContentID())); //NON-NLS } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s' ", foundKeyword.getSearchTerm(), hit.getSnippet())); //NON-NLS - LOGGER.log(Level.SEVERE, "There was a error getting contentID for keyword hit.", ex); //NON-NLS + logger.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s' ", foundKeyword.getSearchTerm(), hit.getSnippet())); //NON-NLS + logger.log(Level.SEVERE, "There was a error getting contentID for keyword hit.", ex); //NON-NLS } } return; @@ -599,7 +611,7 @@ final class RegexQuery implements KeywordSearchQuery { ccAccountInstance.addAttributes(attributes); } catch (TskCoreException | NoCurrentCaseException ex) { - LOGGER.log(Level.SEVERE, "Error creating CCN account instance", ex); //NON-NLS + logger.log(Level.SEVERE, "Error creating CCN account instance", ex); //NON-NLS } From b205a983d3decf990ac1c21a27822abbfaa04b90 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 30 Jul 2018 11:24:54 -0400 Subject: [PATCH 056/105] Module version updates for release 4.8.0 --- Core/manifest.mf | 2 +- Core/nbproject/project.properties | 2 +- Core/nbproject/project.xml | 4 ++-- CoreLibs/manifest.mf | 4 ++-- Experimental/nbproject/project.xml | 4 ++-- ImageGallery/nbproject/project.xml | 4 ++-- KeywordSearch/manifest.mf | 2 +- KeywordSearch/nbproject/project.xml | 4 ++-- RecentActivity/manifest.mf | 2 +- RecentActivity/nbproject/project.xml | 2 +- thunderbirdparser/nbproject/project.xml | 2 +- 11 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Core/manifest.mf b/Core/manifest.mf index 67d3366e22..5eb077ef30 100644 --- a/Core/manifest.mf +++ b/Core/manifest.mf @@ -2,7 +2,7 @@ Manifest-Version: 1.0 OpenIDE-Module: org.sleuthkit.autopsy.core/10 OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/core/Bundle.properties OpenIDE-Module-Layer: org/sleuthkit/autopsy/core/layer.xml -OpenIDE-Module-Implementation-Version: 23 +OpenIDE-Module-Implementation-Version: 24 OpenIDE-Module-Requires: org.openide.windows.WindowManager AutoUpdate-Show-In-Client: true AutoUpdate-Essential-Module: true diff --git a/Core/nbproject/project.properties b/Core/nbproject/project.properties index 9ff74aca14..80bb473653 100644 --- a/Core/nbproject/project.properties +++ b/Core/nbproject/project.properties @@ -46,5 +46,5 @@ nbm.homepage=http://www.sleuthkit.org/ nbm.module.author=Brian Carrier nbm.needs.restart=true source.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8.0-sources.jar -spec.version.base=10.11 +spec.version.base=10.12 diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index 46ad7c5426..859db9f0d2 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -251,7 +251,7 @@ 3 - 1.1 + 1.2 @@ -499,7 +499,7 @@ ext/xmpcore-5.1.3.jar release/modules/ext/xmpcore-5.1.3.jar - + ext/SparseBitSet-1.1.jar release/modules/ext/SparseBitSet-1.1.jar diff --git a/CoreLibs/manifest.mf b/CoreLibs/manifest.mf index e2386f67ce..24af339d11 100644 --- a/CoreLibs/manifest.mf +++ b/CoreLibs/manifest.mf @@ -1,8 +1,8 @@ Manifest-Version: 1.0 OpenIDE-Module: org.sleuthkit.autopsy.corelibs/3 -OpenIDE-Module-Implementation-Version: 4 +OpenIDE-Module-Implementation-Version: 5 OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/corelibs/Bundle.properties -OpenIDE-Module-Specification-Version: 1.1 +OpenIDE-Module-Specification-Version: 1.2 AutoUpdate-Show-In-Client: true AutoUpdate-Essential-Module: true diff --git a/Experimental/nbproject/project.xml b/Experimental/nbproject/project.xml index 6d3d3f6730..c0a18a9922 100644 --- a/Experimental/nbproject/project.xml +++ b/Experimental/nbproject/project.xml @@ -135,7 +135,7 @@ 10 - 10.11 + 10.12 @@ -144,7 +144,7 @@ 3 - 1.1 + 1.2 diff --git a/ImageGallery/nbproject/project.xml b/ImageGallery/nbproject/project.xml index 0fdad950f2..dcaa641e75 100644 --- a/ImageGallery/nbproject/project.xml +++ b/ImageGallery/nbproject/project.xml @@ -127,7 +127,7 @@ 10 - 10.11 + 10.12 @@ -136,7 +136,7 @@ 3 - 1.1 + 1.2 diff --git a/KeywordSearch/manifest.mf b/KeywordSearch/manifest.mf index 9f3126687e..5b53ffe61d 100644 --- a/KeywordSearch/manifest.mf +++ b/KeywordSearch/manifest.mf @@ -1,7 +1,7 @@ Manifest-Version: 1.0 AutoUpdate-Show-In-Client: true OpenIDE-Module: org.sleuthkit.autopsy.keywordsearch/6 -OpenIDE-Module-Implementation-Version: 19 +OpenIDE-Module-Implementation-Version: 20 OpenIDE-Module-Install: org/sleuthkit/autopsy/keywordsearch/Installer.class OpenIDE-Module-Layer: org/sleuthkit/autopsy/keywordsearch/layer.xml OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/keywordsearch/Bundle.properties diff --git a/KeywordSearch/nbproject/project.xml b/KeywordSearch/nbproject/project.xml index 25142d8119..343dc691e7 100644 --- a/KeywordSearch/nbproject/project.xml +++ b/KeywordSearch/nbproject/project.xml @@ -119,7 +119,7 @@ 10 - 10.11 + 10.12 @@ -128,7 +128,7 @@ 3 - 1.1 + 1.2 diff --git a/RecentActivity/manifest.mf b/RecentActivity/manifest.mf index 3121c6b8ca..c115996776 100644 --- a/RecentActivity/manifest.mf +++ b/RecentActivity/manifest.mf @@ -1,6 +1,6 @@ Manifest-Version: 1.0 OpenIDE-Module: org.sleuthkit.autopsy.recentactivity/6 -OpenIDE-Module-Implementation-Version: 15 +OpenIDE-Module-Implementation-Version: 16 OpenIDE-Module-Layer: org/sleuthkit/autopsy/recentactivity/layer.xml OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/recentactivity/Bundle.properties OpenIDE-Module-Requires: diff --git a/RecentActivity/nbproject/project.xml b/RecentActivity/nbproject/project.xml index fd72fa7dfe..4d85f94e9b 100644 --- a/RecentActivity/nbproject/project.xml +++ b/RecentActivity/nbproject/project.xml @@ -60,7 +60,7 @@ 10 - 10.11 + 10.12 diff --git a/thunderbirdparser/nbproject/project.xml b/thunderbirdparser/nbproject/project.xml index 110c3b8ede..d4c0a0b53d 100644 --- a/thunderbirdparser/nbproject/project.xml +++ b/thunderbirdparser/nbproject/project.xml @@ -36,7 +36,7 @@ 10 - 10.11 + 10.12 From 830f33861136a4fa2253eaaa842861ebabd2fcb7 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Tue, 31 Jul 2018 10:23:06 -0400 Subject: [PATCH 057/105] Fixes for postgres queries --- .../autopsy/report/TableReportGenerator.java | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java index f87851fe87..64f1f509af 100644 --- a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java @@ -582,7 +582,7 @@ class TableReportGenerator { adHocCountQuery += " AND (art.artifact_id = tag.artifact_id) AND (tag.tag_name_id IN (" + tagIDList + ")) "; //NON-NLS } adHocCountQuery += "EXCEPT " + // NON-NLS - "SELECT art.artifact_id FROM blackboard_artifacts AS art, blackboard_attributes AS att1 WHERE (att1.artifact_id = art.artifact_id) AND (art.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + ") AND (att1.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + ")) "; //NON-NLS + "SELECT art.artifact_id FROM blackboard_artifacts AS art, blackboard_attributes AS att1 WHERE (att1.artifact_id = art.artifact_id) AND (art.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + ") AND (att1.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + ")) AS adHocHits"; //NON-NLS int adHocCount = 0; try (SleuthkitCase.CaseDbQuery dbQuery = openCase.getSleuthkitCase().executeQuery(adHocCountQuery)) { @@ -600,7 +600,7 @@ class TableReportGenerator { // Create the query to get the keyword list names if (openCase.getCaseType() == Case.CaseType.MULTI_USER_CASE) { - orderByClause = "ORDER BY convert_to(att.value_text, 'SQL_ASCII') ASC NULLS FIRST"; //NON-NLS + orderByClause = "ORDER BY convert_to(list, 'SQL_ASCII') ASC NULLS FIRST"; //NON-NLS } else { orderByClause = "ORDER BY list ASC"; //NON-NLS } @@ -621,8 +621,9 @@ class TableReportGenerator { "AND (tag.tag_name_id IN (" + tagIDList + ")) "; //NON-NLS } if (adHocCount > 0) { - keywordListQuery += " UNION SELECT \"\" AS list "; + keywordListQuery += " UNION SELECT \'\' AS list "; } + keywordListQuery = "SELECT * FROM ( " + keywordListQuery + " ) kwListNames "; keywordListQuery += "GROUP BY list " + orderByClause; //NON-NLS // Make the table of contents links for each list type @@ -645,17 +646,17 @@ class TableReportGenerator { 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 + logger.log(Level.SEVERE, "Failed to query keyword lists with query " + keywordListQuery, ex); //NON-NLS return; } // Query for keywords, grouped by list if (openCase.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 + orderByClause = "ORDER BY convert_to(list, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS + + "convert_to(keyword, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS + + "convert_to(parent_path, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS + + "convert_to(name, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS + + "convert_to(preview, 'SQL_ASCII') ASC NULLS FIRST"; //NON-NLS } else { orderByClause = "ORDER BY list ASC, keyword ASC, parent_path ASC, name ASC, preview ASC"; //NON-NLS } @@ -684,7 +685,7 @@ class TableReportGenerator { // Query for keywords that are not part of a list String keywordAdHocQuery = - "SELECT art.artifact_id AS artifact_id, art.obj_id AS obj_id, att1.value_text AS keyword, att2.value_text AS preview, \"\" AS list, f.name AS name, f.parent_path AS parent_path " + // NON-NLS + "SELECT art.artifact_id AS artifact_id, art.obj_id AS obj_id, att1.value_text AS keyword, att2.value_text AS preview, \'\' 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, tsk_files AS f " + // NON-NLS "WHERE " + // NON-NLS " (art.artifact_id IN (SELECT art.artifact_id FROM blackboard_artifacts AS art, blackboard_attributes AS att1 WHERE (att1.artifact_id = art.artifact_id) AND (art.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + ") " + // NON-NLS @@ -697,7 +698,7 @@ class TableReportGenerator { "AND (att2.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW.getTypeID() + ") " + // NON-NLS "AND (art.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + ") "; // NON-NLS - String keywordsQuery = keywordListsQuery + " UNION " + keywordAdHocQuery + orderByClause; + String keywordsQuery = "SELECT * FROM ( " + keywordListsQuery + " UNION " + keywordAdHocQuery + " ) kwHits " + orderByClause; try (SleuthkitCase.CaseDbQuery dbQuery = openCase.getSleuthkitCase().executeQuery(keywordsQuery)) { ResultSet resultSet = dbQuery.getResultSet(); @@ -770,7 +771,7 @@ class TableReportGenerator { tableModule.endDataType(); } catch (TskCoreException | SQLException ex) { errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedQueryKWs")); - logger.log(Level.SEVERE, "Failed to query keywords: ", ex); //NON-NLS + logger.log(Level.SEVERE, "Failed to query keywords with query " + keywordsQuery, ex); //NON-NLS } } From dd1bfc106d353f46c1470fcc13f916aeff9b75a7 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 31 Jul 2018 10:38:16 -0400 Subject: [PATCH 058/105] Cleanup. --- .../autopsy/keywordsearch/QueryResults.java | 11 ++--------- .../autopsy/keywordsearch/RegexQuery.java | 17 ++++++++--------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryResults.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryResults.java index 3b7dd81fa0..e27a01b063 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryResults.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryResults.java @@ -41,7 +41,6 @@ import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; -import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; @@ -66,7 +65,7 @@ class QueryResults { * and publishing an event to notify subscribers of the blackboard posts. * * The KeywordSearchQuery is used to do the blackboard posts. - * + * * @param query The query. */ QueryResults(KeywordSearchQuery query) { @@ -221,14 +220,8 @@ class QueryResults { } /* - * Create an artifact if it is determined that one hasn't been - * created yet. + * Post an artifact for the hit to the blackboard. */ - if (content == null) { - logger.log(Level.WARNING, "Cannot add artifact for keyword hit to blackboard without a Content object."); //NON-NLS - continue; // Cycle to the next KeywordHit. - } - BlackboardArtifact artifact = query.postKeywordHitToBlackboard(content, keyword, hit, snippet, query.getKeywordList().getName()); /* diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java index 1706cdef60..9d2717a586 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java @@ -36,7 +36,6 @@ import org.apache.solr.client.solrj.response.QueryResponse; import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrDocumentList; import org.apache.solr.common.params.CursorMarkParams; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; @@ -450,6 +449,14 @@ final class RegexQuery implements KeywordSearchQuery { logger.log(Level.WARNING, "Error adding artifact for keyword hit to blackboard"); //NON-NLS return null; } + + /* + * Credit Card number hits are handled differently + */ + if (originalKeyword.getArtifactAttributeType() == ATTRIBUTE_TYPE.TSK_CARD_NUMBER) { + createCCNAccount(content, foundKeyword, hit, snippet, listName); + return null; + } List attributesList = new ArrayList<>(); attributesList.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD, MODULE_NAME, foundKeyword.getSearchTerm())); @@ -470,14 +477,6 @@ final class RegexQuery implements KeywordSearchQuery { "A problem occurred while checking for existing artifacts for file '%s' (id=%d).", content.getName(), content.getId()), ex); //NON-NLS } - - /* - * Credit Card number hits are handled differently - */ - if (originalKeyword.getArtifactAttributeType() == ATTRIBUTE_TYPE.TSK_CARD_NUMBER) { - createCCNAccount(content, foundKeyword, hit, snippet, listName); - return null; - } /* * Create a "plain vanilla" keyword hit artifact with keyword and From 3fadd00b45f5084d96f431db501b217db1809534 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 31 Jul 2018 10:56:21 -0400 Subject: [PATCH 059/105] Additional cleanup. --- .../org/sleuthkit/autopsy/keywordsearch/LuceneQuery.java | 7 ++++--- .../org/sleuthkit/autopsy/keywordsearch/RegexQuery.java | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LuceneQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LuceneQuery.java index fadc2f5107..b3065dcad6 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LuceneQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LuceneQuery.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -37,6 +37,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.EscapeUtil; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Version; +import org.sleuthkit.datamodel.Blackboard; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -234,8 +235,8 @@ class LuceneQuery implements KeywordSearchQuery { try { SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - org.sleuthkit.datamodel.Blackboard tskBlackboard = tskCase.getBlackboard(); - if (tskBlackboard.artifactExists(content, BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT, attributesList)) { + Blackboard blackboard = tskCase.getBlackboard(); + if (blackboard.artifactExists(content, BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT, attributesList)) { return null; } } catch (NoCurrentCaseException | TskCoreException ex) { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java index 9d2717a586..102682c4fe 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java @@ -49,6 +49,7 @@ import static org.sleuthkit.autopsy.keywordsearch.TermsComponentQuery.KEYWORD_SE import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.AccountFileInstance; +import org.sleuthkit.datamodel.Blackboard; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -468,8 +469,8 @@ final class RegexQuery implements KeywordSearchQuery { try { SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - org.sleuthkit.datamodel.Blackboard tskBlackboard = tskCase.getBlackboard(); - if (tskBlackboard.artifactExists(content, BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT, attributesList)) { + Blackboard blackboard = tskCase.getBlackboard(); + if (blackboard.artifactExists(content, BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT, attributesList)) { return null; } } catch (NoCurrentCaseException | TskCoreException ex) { From fee2e8126459322c0c8cbb44829165ce6847b187 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Wed, 1 Aug 2018 10:44:41 -0400 Subject: [PATCH 060/105] Removed empty space in UI --- .../autopsy/keywordsearch/DropdownSingleTermSearchPanel.form | 2 +- .../autopsy/keywordsearch/DropdownSingleTermSearchPanel.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.form b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.form index 81630d6fa5..95baf22255 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.form +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.form @@ -76,7 +76,7 @@ - + diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.java index 1f6744cced..fc81c092c9 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownSingleTermSearchPanel.java @@ -307,7 +307,7 @@ public class DropdownSingleTermSearchPanel extends AdHocSearchPanel { .addComponent(ingestIndexLabel)) .addComponent(keywordTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 296, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(dataSourceCheckBox)) - .addContainerGap(39, Short.MAX_VALUE)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) From 1198a38f5b1b0c4c11444e93a9e5a92defe4d797 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Wed, 1 Aug 2018 16:20:13 -0400 Subject: [PATCH 061/105] Refactored SQLite parsing functionality out of SQLiteViewer and into SQLiteExtractor --- .../autopsy/contentviewers/SQLiteViewer.java | 245 ++++------------- .../textextraction/SQLiteExtractor.java | 247 ++++++++++++++++++ 2 files changed, 301 insertions(+), 191 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/textextraction/SQLiteExtractor.java diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java index 40a667e3d7..6ace716240 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java @@ -22,22 +22,14 @@ import java.awt.BorderLayout; import java.awt.Component; import java.awt.Cursor; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.TreeMap; import java.util.logging.Level; import javax.swing.JComboBox; import javax.swing.JFileChooser; @@ -48,14 +40,11 @@ import org.openide.util.NbBundle; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.casemodule.services.FileManager; -import org.sleuthkit.autopsy.casemodule.services.Services; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.textextraction.SQLiteExtractor; /** * A file content viewer for SQLite database files. @@ -370,41 +359,12 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { "SQLiteViewer.errorMessage.failedToQueryDatabase=The database tables in the file could not be read.", "SQLiteViewer.errorMessage.failedToinitJDBCDriver=The JDBC driver for SQLite could not be loaded.", "# {0} - exception message", "SQLiteViewer.errorMessage.unexpectedError=An unexpected error occurred:\n{0).",}) - private void processSQLiteFile() { - + private void processSQLiteFile() { tablesDropdownList.removeAllItems(); - // Copy the file to temp folder - String tmpDBPathName; try { - tmpDBPathName = Case.getCurrentCaseThrows().getTempDirectory() + File.separator + sqliteDbFile.getName(); - } catch (NoCurrentCaseException ex) { - logger.log(Level.SEVERE, "Current case has been closed", ex); //NON-NLS - MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_errorMessage_noCurrentCase()); - return; - } - - tmpDbFile = new File(tmpDBPathName); - if (! tmpDbFile.exists()) { - try { - ContentUtils.writeToFile(sqliteDbFile, tmpDbFile); - - // Look for any meta files associated with this DB - WAL, SHM, etc. - findAndCopySQLiteMetaFile(sqliteDbFile, sqliteDbFile.getName() + "-wal"); - findAndCopySQLiteMetaFile(sqliteDbFile, sqliteDbFile.getName() + "-shm"); - } catch (IOException | NoCurrentCaseException | TskCoreException ex) { - logger.log(Level.SEVERE, String.format("Failed to create temp copy of DB file '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS - MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_errorMessage_failedToExtractFile()); - return; - } - } - - try { - // Load the SQLite JDBC driver, if necessary. - Class.forName("org.sqlite.JDBC"); //NON-NLS - connection = DriverManager.getConnection("jdbc:sqlite:" + tmpDBPathName); //NON-NLS - - Map dbTablesMap = getTables(); + connection = SQLiteExtractor.getDatabaseConnection(sqliteDbFile); + Map dbTablesMap = SQLiteExtractor.getTableNameAndSchemaPairs(connection); if (dbTablesMap.isEmpty()) { tablesDropdownList.addItem(Bundle.SQLiteViewer_comboBox_noTableEntry()); tablesDropdownList.setEnabled(false); @@ -413,78 +373,36 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { tablesDropdownList.addItem(tableName); }); } + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Current case has been closed", ex); //NON-NLS + MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_errorMessage_noCurrentCase()); + } catch (IOException | TskCoreException ex) { + logger.log(Level.SEVERE, String.format( + "Failed to create temp copy of DB file '%s' (objId=%d)", //NON-NLS + sqliteDbFile.getName(), sqliteDbFile.getId()), ex); + MessageNotifyUtil.Message.error( + Bundle.SQLiteViewer_errorMessage_failedToExtractFile()); } catch (ClassNotFoundException ex) { - logger.log(Level.SEVERE, String.format("Failed to initialize JDBC SQLite '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS - MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_errorMessage_failedToinitJDBCDriver()); + logger.log(Level.SEVERE, String.format( + "Failed to initialize JDBC SQLite '%s' (objId=%d)", //NON-NLS + sqliteDbFile.getName(), sqliteDbFile.getId()), ex); + MessageNotifyUtil.Message.error( + Bundle.SQLiteViewer_errorMessage_failedToinitJDBCDriver()); } catch (SQLException ex) { - logger.log(Level.SEVERE, String.format("Failed to get tables from DB file '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS - MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_errorMessage_failedToQueryDatabase()); + logger.log(Level.SEVERE, String.format( + "Failed to get tables from DB file '%s' (objId=%d)", //NON-NLS + sqliteDbFile.getName(), sqliteDbFile.getId()), ex); + MessageNotifyUtil.Message.error( + Bundle.SQLiteViewer_errorMessage_failedToQueryDatabase()); } } - /** - * Searches for a meta file associated with the give SQLite db If found, - * copies the file to the temp folder - * - * @param sqliteFile - SQLIte db file being processed - * @param metaFileName name of meta file to look for - */ - private void findAndCopySQLiteMetaFile(AbstractFile sqliteFile, String metaFileName) throws NoCurrentCaseException, TskCoreException, IOException { - Case openCase = Case.getCurrentCaseThrows(); - SleuthkitCase sleuthkitCase = openCase.getSleuthkitCase(); - Services services = new Services(sleuthkitCase); - FileManager fileManager = services.getFileManager(); - List metaFiles = fileManager.findFiles(sqliteFile.getDataSource(), metaFileName, sqliteFile.getParent().getName()); - if (metaFiles != null) { - for (AbstractFile metaFile : metaFiles) { - String tmpMetafilePathName = openCase.getTempDirectory() + File.separator + metaFile.getName(); - File tmpMetafile = new File(tmpMetafilePathName); - ContentUtils.writeToFile(metaFile, tmpMetafile); - } - } - } - - /** - * Gets the table names and schemas from the SQLite database file. - * - * @return A mapping of table names to SQL CREATE TABLE statements. - */ - private Map getTables() throws SQLException { - Map dbTablesMap = new TreeMap<>(); - Statement statement = null; - ResultSet resultSet = null; - try { - statement = connection.createStatement(); - resultSet = statement.executeQuery( - "SELECT name, sql FROM sqlite_master " - + " WHERE type= 'table' " - + " ORDER BY name;"); //NON-NLS - while (resultSet.next()) { - String tableName = resultSet.getString("name"); //NON-NLS - String tableSQL = resultSet.getString("sql"); //NON-NLS - dbTablesMap.put(tableName, tableSQL); - } - } finally { - if (null != resultSet) { - resultSet.close(); - } - if (null != statement) { - statement.close(); - } - } - return dbTablesMap; - } - @NbBundle.Messages({"# {0} - tableName", "SQLiteViewer.selectTable.errorText=Error getting row count for table: {0}" }) private void selectTable(String tableName) { - - try (Statement statement = connection.createStatement(); - ResultSet resultSet = statement.executeQuery( - "SELECT count (*) as count FROM " + tableName)) { //NON-NLS{ - - numRows = resultSet.getInt("count"); + try { + numRows = SQLiteExtractor.getTableRowCount(connection, tableName); numEntriesField.setText(numRows + " entries"); currPage = 1; @@ -504,8 +422,11 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { } } catch (SQLException ex) { - logger.log(Level.SEVERE, String.format("Failed to load table %s from DB file '%s' (objId=%d)", tableName, sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS - MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_selectTable_errorText(tableName)); + logger.log(Level.SEVERE, String.format( + "Failed to load table %s from DB file '%s' (objId=%d)", tableName, //NON-NLS + sqliteDbFile.getName(), sqliteDbFile.getId()), ex); + MessageNotifyUtil.Message.error( + Bundle.SQLiteViewer_selectTable_errorText(tableName)); } } @@ -513,48 +434,22 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { "SQLiteViewer.readTable.errorText=Error getting rows for table: {0}"}) private void readTable(String tableName, int startRow, int numRowsToRead) { - try ( - Statement statement = connection.createStatement(); - ResultSet resultSet = statement.executeQuery( - "SELECT * FROM " + tableName - + " LIMIT " + Integer.toString(numRowsToRead) - + " OFFSET " + Integer.toString(startRow - 1))) { - - ArrayList> rows = resultSetToArrayList(resultSet); + try { + List> rows = SQLiteExtractor.getRowsFromTable( + connection, tableName, startRow, numRowsToRead); if (Objects.nonNull(rows)) { selectedTableView.setupTable(rows); } else { selectedTableView.setupTable(Collections.emptyList()); } } catch (SQLException ex) { - logger.log(Level.SEVERE, String.format("Failed to read table %s from DB file '%s' (objId=%d)", tableName, sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS - MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_readTable_errorText(tableName)); + logger.log(Level.SEVERE, String.format( + "Failed to read table %s from DB file '%s' (objId=%d)", tableName, //NON-NLS + sqliteDbFile.getName(), sqliteDbFile.getId()), ex); + MessageNotifyUtil.Message.error( + Bundle.SQLiteViewer_readTable_errorText(tableName)); } } - - @NbBundle.Messages("SQLiteViewer.BlobNotShown.message=BLOB Data not shown") - private ArrayList> resultSetToArrayList(ResultSet rs) throws SQLException { - ResultSetMetaData metaData = rs.getMetaData(); - int columns = metaData.getColumnCount(); - ArrayList> rowlist = new ArrayList<>(); - while (rs.next()) { - Map row = new LinkedHashMap<>(columns); - for (int i = 1; i <= columns; ++i) { - if (rs.getObject(i) == null) { - row.put(metaData.getColumnName(i), ""); - } else { - if (metaData.getColumnTypeName(i).compareToIgnoreCase("blob") == 0) { - row.put(metaData.getColumnName(i), Bundle.SQLiteViewer_BlobNotShown_message()); - } else { - row.put(metaData.getColumnName(i), rs.getObject(i)); - } - } - } - rowlist.add(row); - } - - return rowlist; - } @NbBundle.Messages({"SQLiteViewer.exportTableToCsv.write.errText=Failed to export table content to csv file.", "SQLiteViewer.exportTableToCsv.FileName=File name: ", @@ -562,60 +457,28 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { }) private void exportTableToCsv(File file) { String tableName = (String) this.tablesDropdownList.getSelectedItem(); - try ( - Statement statement = connection.createStatement(); - ResultSet resultSet = statement.executeQuery("SELECT * FROM " + tableName)) { - List> currentTableRows = resultSetToArrayList(resultSet); + try { + List> currentTableRows = + SQLiteExtractor.getRowsFromTable(connection, tableName); if (Objects.isNull(currentTableRows) || currentTableRows.isEmpty()) { - logger.log(Level.INFO, String.format("The table %s is empty. (objId=%d)", tableName, sqliteDbFile.getId())); //NON-NLS + logger.log(Level.INFO, String.format( + "The table %s is empty. (objId=%d)", tableName, //NON-NLS + sqliteDbFile.getId())); } else { - File csvFile; - String fileName = file.getName(); - if (FilenameUtils.getExtension(fileName).equalsIgnoreCase("csv")) { - csvFile = file; - } else { - csvFile = new File(file.toString() + ".csv"); - } - - try (FileOutputStream out = new FileOutputStream(csvFile, false)) { - - out.write((Bundle.SQLiteViewer_exportTableToCsv_FileName() + csvFile.getName() + "\n").getBytes()); - out.write((Bundle.SQLiteViewer_exportTableToCsv_TableName() + tableName + "\n").getBytes()); - // Set up the column names - Map row = currentTableRows.get(0); - StringBuffer header = new StringBuffer(); - for (Map.Entry col : row.entrySet()) { - String colName = col.getKey(); - if (header.length() > 0) { - header.append(',').append(colName); - } else { - header.append(colName); - } - } - out.write(header.append('\n').toString().getBytes()); - - for (Map maps : currentTableRows) { - StringBuffer valueLine = new StringBuffer(); - maps.values().forEach((value) -> { - if (valueLine.length() > 0) { - valueLine.append(',').append(value.toString()); - } else { - valueLine.append(value.toString()); - } - }); - out.write(valueLine.append('\n').toString().getBytes()); - } - } + SQLiteExtractor.exportTableToCSV(file, tableName, currentTableRows); } } catch (SQLException ex) { - logger.log(Level.SEVERE, String.format("Failed to read table %s from DB file '%s' (objId=%d)", tableName, sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS - MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_readTable_errorText(tableName)); + logger.log(Level.SEVERE, String.format( + "Failed to read table %s from DB file '%s' (objId=%d)", //NON-NLS + tableName, sqliteDbFile.getName(), sqliteDbFile.getId()), ex); + MessageNotifyUtil.Message.error( + Bundle.SQLiteViewer_readTable_errorText(tableName)); } catch (IOException ex) { - logger.log(Level.SEVERE, String.format("Failed to export table %s to file '%s'", tableName, file.getName()), ex); //NON-NLS - MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_exportTableToCsv_write_errText()); + logger.log(Level.SEVERE, String.format( + "Failed to export table %s to file '%s'", tableName, file.getName()), ex); //NON-NLS + MessageNotifyUtil.Message.error( + Bundle.SQLiteViewer_exportTableToCsv_write_errText()); } } - - } diff --git a/Core/src/org/sleuthkit/autopsy/textextraction/SQLiteExtractor.java b/Core/src/org/sleuthkit/autopsy/textextraction/SQLiteExtractor.java new file mode 100755 index 0000000000..c06a626d59 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/textextraction/SQLiteExtractor.java @@ -0,0 +1,247 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013-2018 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.textextraction; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.stream.Collectors; +import org.apache.commons.io.FilenameUtils; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.casemodule.services.FileManager; +import org.sleuthkit.autopsy.casemodule.services.Services; +import org.sleuthkit.autopsy.datamodel.ContentUtils; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Abstracts the need to open (and close) statements and result sets from the + * JDBC. Classes using the SQLiteExtractor must maintain a reference to the + * Connection object generated in getDatabaseConnection. + */ +public class SQLiteExtractor { + + private SQLiteExtractor(){} + + public static Connection getDatabaseConnection(AbstractFile sqliteDbFile) + throws ClassNotFoundException, SQLException, IOException, + NoCurrentCaseException, TskCoreException { + + String tmpDBPathName = Case.getCurrentCaseThrows().getTempDirectory() + + File.separator + sqliteDbFile.getName(); + + moveDbToTempFile(sqliteDbFile, tmpDBPathName); + + // Load the SQLite JDBC driver, if necessary. + Class.forName("org.sqlite.JDBC"); //NON-NLS + Connection connection = DriverManager.getConnection( + "jdbc:sqlite:" + tmpDBPathName); //NON-NLS + return connection; + } + + /** + * Gets the table names and schemas from the SQLite database file. + * + * @return A mapping of table names to SQL CREATE TABLE statements. + */ + public static Map getTableNameAndSchemaPairs(Connection connection) + throws SQLException { + + Map dbTablesMap = new TreeMap<>(); + + try (Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery( + "SELECT name, sql FROM sqlite_master " //NON-NLS + + " WHERE type= 'table' " //NON-NLS + + " ORDER BY name;")){ //NON-NLS + + while (resultSet.next()) { + String tableName = resultSet.getString("name"); //NON-NLS + String tableSQL = resultSet.getString("sql"); //NON-NLS + dbTablesMap.put(tableName, tableSQL); + } + } + + return dbTablesMap; + } + + public static Integer getTableRowCount(Connection connection, + String tableName) throws SQLException { + try (Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery( + "SELECT count (*) as count FROM " + tableName)){ + return resultSet.getInt("count"); + } + } + + public static List> getRowsFromTable(Connection connection, + String tableName) throws SQLException { + try(Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery( + "SELECT * FROM " + tableName)) { + return resultSetToList(resultSet); + } + } + + @NbBundle.Messages({"# {0} - tableName", + "SQLiteExtractor.readTable.errorText=Error getting rows for table: {0}"}) + public static List> getRowsFromTable(Connection connection, String tableName, + int startRow, int numRowsToRead) throws SQLException{ + + try(Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery( + "SELECT * FROM " + tableName + + " LIMIT " + Integer.toString(numRowsToRead) + + " OFFSET " + Integer.toString(startRow - 1))) { + return resultSetToList(resultSet); + } + } + + @NbBundle.Messages({"SQLiteExtractor.exportTableToCsv.write.errText=Failed to export table content to csv file.", + "SQLiteExtractor.exportTableToCsv.FileName=File name: ", + "SQLiteExtractor.exportTableToCsv.TableName=Table name: " + }) + public static void exportTableToCSV(File file, String tableName, + List> keyValuePairsInRows) throws FileNotFoundException, IOException{ + + File csvFile; + String fileName = file.getName(); + if (FilenameUtils.getExtension(fileName).equalsIgnoreCase("csv")) { + csvFile = file; + } else { + csvFile = new File(file.toString() + ".csv"); + } + + try (FileOutputStream out = new FileOutputStream(csvFile, false)) { + + out.write((Bundle.SQLiteExtractor_exportTableToCsv_FileName() + csvFile.getName() + "\n").getBytes()); + out.write((Bundle.SQLiteExtractor_exportTableToCsv_TableName() + tableName + "\n").getBytes()); + + String header = createColumnHeader(keyValuePairsInRows.get(0)).concat("\n"); + out.write(header.getBytes()); + + for (Map maps : keyValuePairsInRows) { + String row = maps.values() + .stream() + .map(Object::toString) + .collect(Collectors.joining(",")).concat("\n"); + out.write(row.getBytes()); + } + } + } + + public static void exportTableToCSV(File file, String tableName, + ResultSet resultSet) throws SQLException, IOException { + exportTableToCSV(file, tableName, resultSetToList(resultSet)); + } + + /** + * The map holds the column name to value pairs for a particular row. For example, (id, 123) + * is a valid key-value pair in the map. + */ + @NbBundle.Messages("SQLiteExtractor.BlobNotShown.message=BLOB Data not shown") + private static List> resultSetToList(ResultSet rs) throws SQLException { + + ResultSetMetaData metaData = rs.getMetaData(); + int columns = metaData.getColumnCount(); + List> keyValuePairsInRows = new ArrayList<>(); + while (rs.next()) { + Map row = new LinkedHashMap<>(columns); + for (int i = 1; i <= columns; ++i) { + if (rs.getObject(i) == null) { + row.put(metaData.getColumnName(i), ""); + } else { + if (metaData.getColumnTypeName(i).compareToIgnoreCase("blob") == 0) { + row.put(metaData.getColumnName(i), Bundle.SQLiteExtractor_BlobNotShown_message()); + } else { + row.put(metaData.getColumnName(i), rs.getObject(i)); + } + } + } + keyValuePairsInRows.add(row); + } + + return keyValuePairsInRows; + } + + private static String createColumnHeader(Map row) { + + return row.entrySet() + .stream() + .map(Map.Entry::getKey) + .collect(Collectors.joining(",")); + } + + private static void moveDbToTempFile(AbstractFile sqliteDbFile, String tempDbPath) + throws IOException, NoCurrentCaseException, TskCoreException { + + File tmpDbFile = new File(tempDbPath); + if (!tmpDbFile.exists()) { + ContentUtils.writeToFile(sqliteDbFile, tmpDbFile); + + // Look for any meta files associated with this DB - WAL, SHM, etc. + findAndCopySQLiteMetaFile(sqliteDbFile, sqliteDbFile.getName() + "-wal"); + findAndCopySQLiteMetaFile(sqliteDbFile, sqliteDbFile.getName() + "-shm"); + } + } + + /** + * Searches for a meta file associated with the give SQLite db If found, + * copies the file to the temp folder + * + * @param sqliteFile - SQLIte db file being processed + * @param metaFileName name of meta file to look for + */ + private static void findAndCopySQLiteMetaFile(AbstractFile sqliteFile, + String metaFileName) throws NoCurrentCaseException, TskCoreException, IOException { + + Case openCase = Case.getCurrentCaseThrows(); + SleuthkitCase sleuthkitCase = openCase.getSleuthkitCase(); + Services services = new Services(sleuthkitCase); + FileManager fileManager = services.getFileManager(); + + List metaFiles = fileManager.findFiles( + sqliteFile.getDataSource(), metaFileName, + sqliteFile.getParent().getName()); + + if (metaFiles != null) { + for (AbstractFile metaFile : metaFiles) { + String tmpMetafilePathName = openCase.getTempDirectory() + + File.separator + metaFile.getName(); + File tmpMetafile = new File(tmpMetafilePathName); + ContentUtils.writeToFile(metaFile, tmpMetafile); + } + } + } +} From 4a637581a04d8b815ab39371a7fa96d46efd132c Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 1 Aug 2018 16:21:56 -0400 Subject: [PATCH 062/105] Change build type back to DEVELOPMENT --- nbproject/project.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nbproject/project.properties b/nbproject/project.properties index 1ce749b501..55a5b67cfd 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -6,8 +6,8 @@ app.name=${branding.token} ### if left unset, version will default to today's date app.version=4.8.0 ### build.type must be one of: DEVELOPMENT, RELEASE -build.type=RELEASE -#build.type=DEVELOPMENT +#build.type=RELEASE +build.type=DEVELOPMENT project.org.netbeans.progress=org-netbeans-api-progress project.org.sleuthkit.autopsy.experimental=Experimental From 7c39e8e6671052c8e40c00b990f46ae64b1c2244 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Wed, 1 Aug 2018 16:58:00 -0400 Subject: [PATCH 063/105] Removed copying DB and DB metafile from SQLiteExtractor --- .../autopsy/contentviewers/SQLiteViewer.java | 53 +++++++- .../textextraction/SQLiteExtractor.java | 114 +++++------------- 2 files changed, 81 insertions(+), 86 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java index 6ace716240..aaaf0a368a 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java @@ -40,11 +40,15 @@ import org.openide.util.NbBundle; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.casemodule.services.FileManager; +import org.sleuthkit.autopsy.casemodule.services.Services; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.autopsy.textextraction.SQLiteExtractor; +import org.sleuthkit.datamodel.SleuthkitCase; /** * A file content viewer for SQLite database files. @@ -363,8 +367,13 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { tablesDropdownList.removeAllItems(); try { - connection = SQLiteExtractor.getDatabaseConnection(sqliteDbFile); + String tmpDBPathName = Case.getCurrentCaseThrows().getTempDirectory() + + File.separator + sqliteDbFile.getName(); + moveDbToTempFile(sqliteDbFile, tmpDBPathName); + + connection = SQLiteExtractor.getDatabaseConnection(tmpDBPathName); Map dbTablesMap = SQLiteExtractor.getTableNameAndSchemaPairs(connection); + if (dbTablesMap.isEmpty()) { tablesDropdownList.addItem(Bundle.SQLiteViewer_comboBox_noTableEntry()); tablesDropdownList.setEnabled(false); @@ -481,4 +490,46 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { Bundle.SQLiteViewer_exportTableToCsv_write_errText()); } } + + private static void moveDbToTempFile(AbstractFile sqliteDbFile, String tempDbPath) + throws IOException, NoCurrentCaseException, TskCoreException { + + File tmpDbFile = new File(tempDbPath); + if (!tmpDbFile.exists()) { + ContentUtils.writeToFile(sqliteDbFile, tmpDbFile); + + // Look for any meta files associated with this DB - WAL, SHM, etc. + findAndCopySQLiteMetaFile(sqliteDbFile, sqliteDbFile.getName() + "-wal"); + findAndCopySQLiteMetaFile(sqliteDbFile, sqliteDbFile.getName() + "-shm"); + } + } + + /** + * Searches for a meta file associated with the give SQLite db If found, + * copies the file to the temp folder + * + * @param sqliteFile - SQLIte db file being processed + * @param metaFileName name of meta file to look for + */ + private static void findAndCopySQLiteMetaFile(AbstractFile sqliteFile, + String metaFileName) throws NoCurrentCaseException, TskCoreException, IOException { + + Case openCase = Case.getCurrentCaseThrows(); + SleuthkitCase sleuthkitCase = openCase.getSleuthkitCase(); + Services services = new Services(sleuthkitCase); + FileManager fileManager = services.getFileManager(); + + List metaFiles = fileManager.findFiles( + sqliteFile.getDataSource(), metaFileName, + sqliteFile.getParent().getName()); + + if (metaFiles != null) { + for (AbstractFile metaFile : metaFiles) { + String tmpMetafilePathName = openCase.getTempDirectory() + + File.separator + metaFile.getName(); + File tmpMetafile = new File(tmpMetafilePathName); + ContentUtils.writeToFile(metaFile, tmpMetafile); + } + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/textextraction/SQLiteExtractor.java b/Core/src/org/sleuthkit/autopsy/textextraction/SQLiteExtractor.java index c06a626d59..a3966c76c5 100755 --- a/Core/src/org/sleuthkit/autopsy/textextraction/SQLiteExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/textextraction/SQLiteExtractor.java @@ -36,38 +36,23 @@ import java.util.TreeMap; import java.util.stream.Collectors; import org.apache.commons.io.FilenameUtils; import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.casemodule.services.FileManager; -import org.sleuthkit.autopsy.casemodule.services.Services; -import org.sleuthkit.autopsy.datamodel.ContentUtils; -import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.SleuthkitCase; -import org.sleuthkit.datamodel.TskCoreException; /** * Abstracts the need to open (and close) statements and result sets from the * JDBC. Classes using the SQLiteExtractor must maintain a reference to the * Connection object generated in getDatabaseConnection. */ -public class SQLiteExtractor { +public final class SQLiteExtractor { private SQLiteExtractor(){} - public static Connection getDatabaseConnection(AbstractFile sqliteDbFile) - throws ClassNotFoundException, SQLException, IOException, - NoCurrentCaseException, TskCoreException { - - String tmpDBPathName = Case.getCurrentCaseThrows().getTempDirectory() + - File.separator + sqliteDbFile.getName(); - - moveDbToTempFile(sqliteDbFile, tmpDBPathName); + public static Connection getDatabaseConnection(String dbPath) + throws ClassNotFoundException, SQLException { // Load the SQLite JDBC driver, if necessary. Class.forName("org.sqlite.JDBC"); //NON-NLS - Connection connection = DriverManager.getConnection( - "jdbc:sqlite:" + tmpDBPathName); //NON-NLS - return connection; + return DriverManager.getConnection( + "jdbc:sqlite:" + dbPath); //NON-NLS } /** @@ -155,7 +140,8 @@ public class SQLiteExtractor { String row = maps.values() .stream() .map(Object::toString) - .collect(Collectors.joining(",")).concat("\n"); + .collect(Collectors.joining(",")) + .concat("\n"); out.write(row.getBytes()); } } @@ -166,35 +152,6 @@ public class SQLiteExtractor { exportTableToCSV(file, tableName, resultSetToList(resultSet)); } - /** - * The map holds the column name to value pairs for a particular row. For example, (id, 123) - * is a valid key-value pair in the map. - */ - @NbBundle.Messages("SQLiteExtractor.BlobNotShown.message=BLOB Data not shown") - private static List> resultSetToList(ResultSet rs) throws SQLException { - - ResultSetMetaData metaData = rs.getMetaData(); - int columns = metaData.getColumnCount(); - List> keyValuePairsInRows = new ArrayList<>(); - while (rs.next()) { - Map row = new LinkedHashMap<>(columns); - for (int i = 1; i <= columns; ++i) { - if (rs.getObject(i) == null) { - row.put(metaData.getColumnName(i), ""); - } else { - if (metaData.getColumnTypeName(i).compareToIgnoreCase("blob") == 0) { - row.put(metaData.getColumnName(i), Bundle.SQLiteExtractor_BlobNotShown_message()); - } else { - row.put(metaData.getColumnName(i), rs.getObject(i)); - } - } - } - keyValuePairsInRows.add(row); - } - - return keyValuePairsInRows; - } - private static String createColumnHeader(Map row) { return row.entrySet() @@ -203,45 +160,32 @@ public class SQLiteExtractor { .collect(Collectors.joining(",")); } - private static void moveDbToTempFile(AbstractFile sqliteDbFile, String tempDbPath) - throws IOException, NoCurrentCaseException, TskCoreException { - - File tmpDbFile = new File(tempDbPath); - if (!tmpDbFile.exists()) { - ContentUtils.writeToFile(sqliteDbFile, tmpDbFile); - - // Look for any meta files associated with this DB - WAL, SHM, etc. - findAndCopySQLiteMetaFile(sqliteDbFile, sqliteDbFile.getName() + "-wal"); - findAndCopySQLiteMetaFile(sqliteDbFile, sqliteDbFile.getName() + "-shm"); - } - } - /** - * Searches for a meta file associated with the give SQLite db If found, - * copies the file to the temp folder - * - * @param sqliteFile - SQLIte db file being processed - * @param metaFileName name of meta file to look for + * The map holds the column name to value pairs for a particular row. For example, (id, 123) + * is a valid key-value pair in the map. */ - private static void findAndCopySQLiteMetaFile(AbstractFile sqliteFile, - String metaFileName) throws NoCurrentCaseException, TskCoreException, IOException { + @NbBundle.Messages("SQLiteExtractor.BlobNotShown.message=BLOB Data not shown") + private static List> resultSetToList(ResultSet resultSet) throws SQLException { - Case openCase = Case.getCurrentCaseThrows(); - SleuthkitCase sleuthkitCase = openCase.getSleuthkitCase(); - Services services = new Services(sleuthkitCase); - FileManager fileManager = services.getFileManager(); - - List metaFiles = fileManager.findFiles( - sqliteFile.getDataSource(), metaFileName, - sqliteFile.getParent().getName()); - - if (metaFiles != null) { - for (AbstractFile metaFile : metaFiles) { - String tmpMetafilePathName = openCase.getTempDirectory() + - File.separator + metaFile.getName(); - File tmpMetafile = new File(tmpMetafilePathName); - ContentUtils.writeToFile(metaFile, tmpMetafile); + ResultSetMetaData metaData = resultSet.getMetaData(); + int columns = metaData.getColumnCount(); + List> keyValuePairsInRows = new ArrayList<>(); + while (resultSet.next()) { + Map row = new LinkedHashMap<>(columns); + for (int i = 1; i <= columns; ++i) { + if (resultSet.getObject(i) == null) { + row.put(metaData.getColumnName(i), ""); + } else { + if (metaData.getColumnTypeName(i).compareToIgnoreCase("blob") == 0) { + row.put(metaData.getColumnName(i), Bundle.SQLiteExtractor_BlobNotShown_message()); + } else { + row.put(metaData.getColumnName(i), resultSet.getObject(i)); + } + } } + keyValuePairsInRows.add(row); } + + return keyValuePairsInRows; } } From a1c4db14bd55b1c9567f2886a7698a5b7707c1d2 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Thu, 2 Aug 2018 10:22:08 -0400 Subject: [PATCH 064/105] Codacy issues resolved. --- .../contentviewer/DataContentViewerOtherCases.java | 1 - .../contentviewer/DataContentViewerOtherCasesTableModel.java | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java index 635605a904..6579b15e08 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java @@ -49,7 +49,6 @@ import javax.swing.JPanel; import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; -import javax.swing.table.TableColumnModel; import org.joda.time.DateTimeZone; import org.joda.time.LocalDateTime; import org.openide.nodes.Node; diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java index 9ae79259c2..1f04f1f478 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java @@ -172,6 +172,8 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel { case COMMENT: value = nodeData.getComment(); break; + default: // This shouldn't occur! Use default "No data" value. + break; } return value; } From 8aba921666c74b8fb817af405b8c6e6d1849fcda Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Thu, 2 Aug 2018 12:17:48 -0400 Subject: [PATCH 065/105] Functional SevenZipExtractor using standard interface. SevenZipException exception handling during extract vs extractSlow still untested --- .../SevenZipExtractor.java | 371 +++++++++++++----- 1 file changed, 267 insertions(+), 104 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java index ee9415ddca..a959345ca6 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java @@ -25,22 +25,27 @@ import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import net.sf.sevenzipjbinding.ArchiveFormat; import static net.sf.sevenzipjbinding.ArchiveFormat.RAR; +import net.sf.sevenzipjbinding.ExtractAskMode; import net.sf.sevenzipjbinding.ISequentialOutStream; import net.sf.sevenzipjbinding.ISevenZipInArchive; import net.sf.sevenzipjbinding.SevenZip; import net.sf.sevenzipjbinding.SevenZipException; import net.sf.sevenzipjbinding.SevenZipNativeInitializationException; -import net.sf.sevenzipjbinding.simple.ISimpleInArchive; -import net.sf.sevenzipjbinding.simple.ISimpleInArchiveItem; import net.sf.sevenzipjbinding.ExtractOperationResult; +import net.sf.sevenzipjbinding.IArchiveExtractCallback; +import net.sf.sevenzipjbinding.ICryptoGetTextPassword; +import net.sf.sevenzipjbinding.PropID; import org.netbeans.api.progress.ProgressHandle; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; @@ -167,19 +172,22 @@ class SevenZipExtractor { * * @return true if potential zip bomb, false otherwise */ - private boolean isZipBombArchiveItemCheck(AbstractFile archiveFile, ISimpleInArchiveItem archiveFileItem, ConcurrentHashMap depthMap, String escapedFilePath) { + private boolean isZipBombArchiveItemCheck(AbstractFile archiveFile, ISevenZipInArchive inArchive, int inArchiveItemIndex, ConcurrentHashMap depthMap, String escapedFilePath) { try { - final Long archiveItemSize = archiveFileItem.getSize(); + final Long archiveItemSize = (Long) inArchive.getProperty( + inArchiveItemIndex, PropID.SIZE); //skip the check for small files if (archiveItemSize == null || archiveItemSize < MIN_COMPRESSION_RATIO_SIZE) { return false; } - final Long archiveItemPackedSize = archiveFileItem.getPackedSize(); + final Long archiveItemPackedSize = (Long) inArchive.getProperty( + inArchiveItemIndex, PropID.PACKED_SIZE); if (archiveItemPackedSize == null || archiveItemPackedSize <= 0) { - logger.log(Level.WARNING, "Cannot getting compression ratio, cannot detect if zipbomb: {0}, item: {1}", new Object[]{archiveFile.getName(), archiveFileItem.getPath()}); //NON-NLS + logger.log(Level.WARNING, "Cannot getting compression ratio, cannot detect if zipbomb: {0}, item: {1}", //NON-NLS + new Object[]{archiveFile.getName(), (String) inArchive.getProperty(inArchiveItemIndex, PropID.PATH)}); //NON-NLS return false; } @@ -366,8 +374,9 @@ class SevenZipExtractor { * * @throws SevenZipException */ - private String getPathInArchive(ISimpleInArchiveItem item, int itemNumber, AbstractFile archiveFile) throws SevenZipException { - String pathInArchive = item.getPath(); + private String getPathInArchive(ISevenZipInArchive archive, int inArchiveItemIndex, AbstractFile archiveFile) throws SevenZipException { + String pathInArchive = (String) archive.getProperty( + inArchiveItemIndex, PropID.PATH); if (pathInArchive == null || pathInArchive.isEmpty()) { //some formats (.tar.gz) may not be handled correctly -- file in archive has no name/path @@ -400,7 +409,7 @@ class SevenZipExtractor { } } if (useName == null) { - pathInArchive = "/" + archName + "/" + Integer.toString(itemNumber); + pathInArchive = "/" + archName + "/" + Integer.toString(inArchiveItemIndex); } else { pathInArchive = "/" + useName; } @@ -428,69 +437,6 @@ class SevenZipExtractor { return node == null ? null : archiveFilePath + "/" + node.getFileName(); } - /** - * Unpack an archive item to the disk using a password if specified. - * - * @param item - the archive item to unpack - * @param unpackedNode - the unpackedNode to add derivedInfo to - * @param password - the password for the archive, null if not - * used - * @param freeDiskSpace - the amount of free disk space - * @param uniqueExtractedName - the name of the file to extract the item to - * - * @return unpackedNode - the updated unpackedNode - * - * @throws SevenZipException - */ - private SevenZipExtractor.UnpackedTree.UnpackedNode unpackNode(ISimpleInArchiveItem item, SevenZipExtractor.UnpackedTree.UnpackedNode unpackedNode, String password, long freeDiskSpace, String uniqueExtractedName) throws SevenZipException { - //unpack locally if a file - final String localAbsPath = moduleDirAbsolute + File.separator + uniqueExtractedName; - final String localRelPath = moduleDirRelative + File.separator + uniqueExtractedName; - final Date createTime = item.getCreationTime(); - final Date accessTime = item.getLastAccessTime(); - final Date writeTime = item.getLastWriteTime(); - final long createtime = createTime == null ? 0L : createTime.getTime() / 1000; - final long modtime = writeTime == null ? 0L : writeTime.getTime() / 1000; - final long accesstime = accessTime == null ? 0L : accessTime.getTime() / 1000; - SevenZipExtractor.UnpackStream unpackStream = null; - boolean isDir = item.isFolder(); - if (!isDir) { - try { - // NOTE: item.getSize() may return null in case of certain - // archiving formats. Eg: BZ2 - if (item.getSize() != null) { - unpackStream = new SevenZipExtractor.KnownSizeUnpackStream(localAbsPath, item.getSize()); - } else { - unpackStream = new SevenZipExtractor.UnknownSizeUnpackStream(localAbsPath, freeDiskSpace); - } - ExtractOperationResult result; - if (password == null) { - result = item.extractSlow(unpackStream); - } else { - result = item.extractSlow(unpackStream, password); - } - if (result != ExtractOperationResult.OK) { - logger.log(Level.WARNING, "Extraction of : {0} encountered error {1}", new Object[]{localAbsPath, result}); //NON-NLS - return null; - } - - } catch (SevenZipException e) { - //could be something unexpected with this file, move on - logger.log(Level.WARNING, "Could not extract file from archive: " + localAbsPath, e); //NON-NLS - } finally { - if (unpackStream != null) { - //record derived data in unode, to be traversed later after unpacking the archive - unpackedNode.addDerivedInfo(unpackStream.getSize(), !isDir, - 0L, createtime, accesstime, modtime, localRelPath); - unpackStream.close(); - } - } - } else { // this is a directory, size is always 0 - unpackedNode.addDerivedInfo(0, !isDir, 0L, createtime, accesstime, modtime, localRelPath); - } - return unpackedNode; - } - /** * Unpack the file to local folder and return a list of derived files * @@ -530,6 +476,8 @@ class SevenZipExtractor { List unpackedFiles = Collections.emptyList(); ISevenZipInArchive inArchive = null; + Map archiveDetailsMap = new LinkedHashMap<>(); + SevenZipContentReadStream stream = null; final ProgressHandle progress = ProgressHandle.createHandle(Bundle.EmbeddedFileExtractorIngestModule_ArchiveExtractor_moduleName()); //recursion depth check for zip bomb @@ -590,7 +538,7 @@ class SevenZipExtractor { logger.log(Level.INFO, "Count of items in archive: {0}: {1}", new Object[]{escapedArchiveFilePath, numItems}); //NON-NLS progress.start(numItems); progressStarted = true; - final ISimpleInArchive simpleInArchive = inArchive.getSimpleInterface(); + progress.progress(archiveFile.getName() + ": Analyzing archive metadata and creating local files"); //setup the archive local root folder final String uniqueArchiveFileName = FileUtil.escapeFileName(EmbeddedFileExtractorIngestModule.getUniqueName(archiveFile)); @@ -614,25 +562,22 @@ class SevenZipExtractor { //currently getFreeDiskSpace always returns DISK_FREE_SPACE_UNKNOWN freeDiskSpace = IngestMonitor.DISK_FREE_SPACE_UNKNOWN; } - //unpack and process every item in archive - int itemNumber = 0; - for (ISimpleInArchiveItem item : simpleInArchive.getArchiveItems()) { - String pathInArchive = getPathInArchive(item, itemNumber, archiveFile); + for (int inArchiveItemIndex = 0; inArchiveItemIndex < numItems; inArchiveItemIndex++) { + String pathInArchive = getPathInArchive(inArchive, inArchiveItemIndex, archiveFile); + String archiveItemPath = (String) inArchive.getProperty( + inArchiveItemIndex, PropID.PATH); + Long archiveItemSize = (Long) inArchive.getProperty( + inArchiveItemIndex, PropID.SIZE); - //query for path in db - ++itemNumber; - - //check if possible zip bomb - if (isZipBombArchiveItemCheck(archiveFile, item, depthMap, escapedArchiveFilePath)) { + if (isZipBombArchiveItemCheck(archiveFile, inArchive, inArchiveItemIndex, depthMap, escapedArchiveFilePath)) { unpackSuccessful = false; return unpackSuccessful; } - SevenZipExtractor.UnpackedTree.UnpackedNode unpackedNode = unpackedTree.addNode(pathInArchive); - //update progress bar - progress.progress(archiveFile.getName() + ": " + item.getPath(), processedItems); - final boolean isEncrypted = item.isEncrypted(); + SevenZipExtractor.UnpackedTree.UnpackedNode unpackedNode = unpackedTree.addNode(pathInArchive); + + final boolean isEncrypted = (Boolean) inArchive.getProperty(inArchiveItemIndex, PropID.ENCRYPTED); if (isEncrypted && password == null) { logger.log(Level.WARNING, "Skipping encrypted file in archive: {0}", pathInArchive); //NON-NLS @@ -642,20 +587,21 @@ class SevenZipExtractor { } else { fullEncryption = false; } + // NOTE: item.getSize() may return null in case of certain // archiving formats. Eg: BZ2 //check if unpacking this file will result in out of disk space //this is additional to zip bomb prevention mechanism - if (freeDiskSpace != IngestMonitor.DISK_FREE_SPACE_UNKNOWN && item.getSize() != null && item.getSize() > 0) { //if free space is known and file is not empty. - long newDiskSpace = freeDiskSpace - item.getSize(); + if (freeDiskSpace != IngestMonitor.DISK_FREE_SPACE_UNKNOWN && archiveItemSize != null && archiveItemSize > 0) { //if free space is known and file is not empty. + long newDiskSpace = freeDiskSpace - archiveItemSize; if (newDiskSpace < MIN_FREE_DISK_SPACE) { String msg = NbBundle.getMessage(SevenZipExtractor.class, "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.notEnoughDiskSpace.msg", - escapedArchiveFilePath, item.getPath()); + escapedArchiveFilePath, archiveItemPath); String details = NbBundle.getMessage(SevenZipExtractor.class, "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.notEnoughDiskSpace.details"); services.postMessage(IngestMessage.createErrorMessage(EmbeddedFileExtractorModuleFactory.getModuleName(), msg, details)); - logger.log(Level.INFO, "Skipping archive item due to insufficient disk space: {0}, {1}", new String[]{escapedArchiveFilePath, item.getPath()}); //NON-NLS + logger.log(Level.INFO, "Skipping archive item due to insufficient disk space: {0}, {1}", new String[]{escapedArchiveFilePath, archiveItemPath}); //NON-NLS logger.log(Level.INFO, "Available disk space: {0}", new Object[]{freeDiskSpace}); //NON-NLS unpackSuccessful = false; continue; //skip this file @@ -664,42 +610,61 @@ class SevenZipExtractor { freeDiskSpace = newDiskSpace; } } - final String uniqueExtractedName = FileUtil.escapeFileName(uniqueArchiveFileName + File.separator + (item.getItemIndex() / 1000) + File.separator + item.getItemIndex() + "_" + new File(pathInArchive).getName()); + final String uniqueExtractedName = FileUtil.escapeFileName(uniqueArchiveFileName + File.separator + (inArchiveItemIndex / 1000) + File.separator + inArchiveItemIndex + "_" + new File(pathInArchive).getName()); + final String localAbsPath = moduleDirAbsolute + File.separator + uniqueExtractedName; + final String localRelPath = moduleDirRelative + File.separator + uniqueExtractedName; //create local dirs and empty files before extracted - File localFile = new java.io.File(moduleDirAbsolute + File.separator + uniqueExtractedName); + File localFile = new java.io.File(localAbsPath); //cannot rely on files in top-bottom order if (!localFile.exists()) { try { - if (item.isFolder()) { + if ((Boolean) inArchive.getProperty( + inArchiveItemIndex, PropID.IS_FOLDER)) { localFile.mkdirs(); } else { localFile.getParentFile().mkdirs(); try { localFile.createNewFile(); } catch (IOException e) { - logger.log(Level.SEVERE, "Error creating extracted file: " + localFile.getAbsolutePath(), e); //NON-NLS + logger.log(Level.SEVERE, "Error creating extracted file: " + + localFile.getAbsolutePath(), e); //NON-NLS } } } catch (SecurityException e) { - logger.log(Level.SEVERE, "Error setting up output path for unpacked file: {0}", pathInArchive); //NON-NLS + logger.log(Level.SEVERE, "Error setting up output path for unpacked file: {0}", + pathInArchive); //NON-NLS //TODO consider bail out / msg to the user } } // skip the rest of this loop if we couldn't create the file + //continue will skip details from being added to the map if (localFile.exists() == false) { continue; } - //find this node in the hierarchy, create if neede; - unpackedNode = unpackNode(item, unpackedNode, password, - freeDiskSpace, uniqueExtractedName); - if (unpackedNode == null) { - unpackSuccessful = false; - } - //update units for progress bar - ++processedItems; + //Store archiveItemIndex with local paths and unpackedNode reference. + //Necessary for the extract call back to write the current archive + //file to the correct disk location and to correctly update it's + //corresponding unpackedNode + archiveDetailsMap.put(inArchiveItemIndex, new InArchiveItemDetails( + unpackedNode, localAbsPath, localRelPath)); } + + int[] extractionIndices = getExtractableFilesFromArchiveDetails(archiveDetailsMap); + + StandardIArchiveExtractCallback archiveCallBack + = new StandardIArchiveExtractCallback( + inArchive, archiveFile, progress, + archiveDetailsMap, password, freeDiskSpace); + + //According to the documentation, indices in sorted order are optimal + //for efficiency. Hence, the LinkedHashMap and linear processing of + //inArchiveItemIndex. + inArchive.extract(extractionIndices, false, archiveCallBack); + + unpackSuccessful = unpackSuccessful & archiveCallBack.getSuccessFlag(); + // add them to the DB. We wait until the end so that we have the metadata on all of the // intermediate nodes since the order is not guaranteed try { @@ -799,6 +764,21 @@ class SevenZipExtractor { return unpackSuccessful; } + /** + * Produce a list of archive indices needed for the call to extract, which + * will open the archive and begin unpacking the files. + */ + private int[] getExtractableFilesFromArchiveDetails( + Map archiveDetailsMap) { + + Integer[] wrappedExtractionIndices = archiveDetailsMap.keySet() + .toArray(new Integer[archiveDetailsMap.size()]); + + return Arrays.stream(wrappedExtractionIndices) + .mapToInt(Integer::intValue) + .toArray(); + } + /** * Stream used to unpack the archive to local file */ @@ -933,6 +913,188 @@ class SevenZipExtractor { } } + /** + * Wrapper for necessary details used in StandardIArchiveExtractCallback + */ + private static class InArchiveItemDetails { + + private SevenZipExtractor.UnpackedTree.UnpackedNode unpackedNode; + private String localAbsPath; + private String localRelPath; + + public InArchiveItemDetails( + SevenZipExtractor.UnpackedTree.UnpackedNode unpackedNode, + String localAbsPath, String localRelPath) { + this.unpackedNode = unpackedNode; + this.localAbsPath = localAbsPath; + this.localRelPath = localRelPath; + } + + public SevenZipExtractor.UnpackedTree.UnpackedNode getUnpackedNode() { + return unpackedNode; + } + + public String getLocalAbsPath() { + return localAbsPath; + } + + public String getLocalRelPath() { + return localRelPath; + } + } + + /** + * Call back class used by extract to expand archive files. This is the most + * efficient way to process according to the sevenzip binding documentation. + */ + private static class StandardIArchiveExtractCallback + implements IArchiveExtractCallback, ICryptoGetTextPassword { + + private int inArchiveItemIndex; + private ISevenZipInArchive inArchive; + private SevenZipExtractor.UnpackStream unpackStream = null; + private long freeDiskSpace; + private Map archiveDetailsMap; + private ProgressHandle progressHandle; + private AbstractFile archiveFile; + + private long createTimeInSeconds; + private long modTimeInSeconds; + private long accessTimeInSeconds; + + private boolean skipExtraction; + private String password; + + private boolean unpackSuccessful = true; + + public StandardIArchiveExtractCallback(ISevenZipInArchive inArchive, + AbstractFile archiveFile, ProgressHandle progressHandle, + Map archiveDetailsMap, + String password, long freeDiskSpace) { + + this.inArchive = inArchive; + this.freeDiskSpace = freeDiskSpace; + this.progressHandle = progressHandle; + this.archiveFile = archiveFile; + this.archiveDetailsMap = archiveDetailsMap; + this.password = password; + } + + @Override + public ISequentialOutStream getStream( + int i, ExtractAskMode EAM) throws SevenZipException { + + inArchiveItemIndex = i; + + skipExtraction = (Boolean) inArchive + .getProperty(inArchiveItemIndex, PropID.IS_FOLDER); + if (skipExtraction || EAM != ExtractAskMode.EXTRACT) { + return null; + } + + final Long archiveItemSize = (Long) inArchive.getProperty( + inArchiveItemIndex, PropID.SIZE); + final String localAbsPath = archiveDetailsMap.get( + inArchiveItemIndex).getLocalAbsPath(); + + if (archiveItemSize != null) { + unpackStream = new SevenZipExtractor.KnownSizeUnpackStream( + localAbsPath, archiveItemSize); + } else { + unpackStream = new SevenZipExtractor.UnknownSizeUnpackStream( + localAbsPath, freeDiskSpace); + } + + return unpackStream; + } + + @Override + public void prepareOperation(ExtractAskMode eam) throws SevenZipException { + final Date createTime = (Date) inArchive.getProperty( + inArchiveItemIndex, PropID.CREATION_TIME); + final Date accessTime = (Date) inArchive.getProperty( + inArchiveItemIndex, PropID.LAST_ACCESS_TIME); + final Date writeTime = (Date) inArchive.getProperty( + inArchiveItemIndex, PropID.LAST_WRITE_TIME); + + createTimeInSeconds = createTime == null ? 0L + : createTime.getTime() / 1000; + modTimeInSeconds = writeTime == null ? 0L + : writeTime.getTime() / 1000; + accessTimeInSeconds = accessTime == null ? 0L + : accessTime.getTime() / 1000; + } + + /** + * Pull necessary details from map to appropriately update unpackedNode + * info and provide useful logging messages. + * + * + * @param EOR - ExtractOperationResult + * + * @throws SevenZipException + */ + @Override + public void setOperationResult(ExtractOperationResult EOR) throws SevenZipException { + final SevenZipExtractor.UnpackedTree.UnpackedNode unpackedNode + = archiveDetailsMap.get(inArchiveItemIndex).getUnpackedNode(); + final String localRelPath = archiveDetailsMap.get( + inArchiveItemIndex).getLocalRelPath(); + final String localAbsPath = archiveDetailsMap.get( + inArchiveItemIndex).getLocalAbsPath(); + + progressHandle.progress(archiveFile.getName() + ": " + + (String) inArchive.getProperty(inArchiveItemIndex, PropID.PATH), + inArchiveItemIndex); + + if (skipExtraction) { + unpackedNode.addDerivedInfo(0, + !(Boolean) inArchive.getProperty(inArchiveItemIndex, PropID.IS_FOLDER), + 0L, createTimeInSeconds, accessTimeInSeconds, modTimeInSeconds, + localRelPath); + return; + } + + //TODO - causes unpack to be unsuccessful, implement fix. + if (EOR != ExtractOperationResult.OK) { + logger.log(Level.WARNING, "Extraction of : {0} encountered error {1}", //NON-NLS + new Object[]{localAbsPath, EOR}); + unpackSuccessful = false; + } + + //record derived data in unode, to be traversed later after unpacking the archive + unpackedNode.addDerivedInfo(unpackStream.getSize(), + !(Boolean) inArchive.getProperty(inArchiveItemIndex, PropID.IS_FOLDER), + 0L, createTimeInSeconds, accessTimeInSeconds, modTimeInSeconds, localRelPath); + + unpackStream.close(); + } + + @Override + public void setTotal(long l) throws SevenZipException { + } + + @Override + public void setCompleted(long l) throws SevenZipException { + } + + /** + * Called when opening encrypted archive files. + * + * @return - Password supplied by user + * + * @throws SevenZipException + */ + @Override + public String cryptoGetTextPassword() throws SevenZipException { + return password; + } + + public boolean getSuccessFlag() { + return unpackSuccessful; + } + } + /** * Representation of the files in the archive. Used to track of local tree * file hierarchy, archive depth, and files created to easily and reliably @@ -1290,7 +1452,8 @@ class SevenZipExtractor { } /** - * Set the flag which identifies whether this file has been determined to be a zip bomb to true. + * Set the flag which identifies whether this file has been determined + * to be a zip bomb to true. */ synchronized void flagAsZipBomb() { flaggedAsZipBomb = true; From b1d242ace39b127584869bb13b608b6428a5549c Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Thu, 2 Aug 2018 12:22:43 -0400 Subject: [PATCH 066/105] Fixed //NON-NLS comment to be inline with the logger messages --- .../modules/embeddedfileextractor/SevenZipExtractor.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java index a959345ca6..ca1dd28233 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java @@ -627,12 +627,12 @@ class SevenZipExtractor { try { localFile.createNewFile(); } catch (IOException e) { - logger.log(Level.SEVERE, "Error creating extracted file: " - + localFile.getAbsolutePath(), e); //NON-NLS + logger.log(Level.SEVERE, "Error creating extracted file: "//NON-NLS + + localFile.getAbsolutePath(), e); } } } catch (SecurityException e) { - logger.log(Level.SEVERE, "Error setting up output path for unpacked file: {0}", + logger.log(Level.SEVERE, "Error setting up output path for unpacked file: {0}", //NON-NLS pathInArchive); //NON-NLS //TODO consider bail out / msg to the user } From 74bf4bd272c5cb2d85aa589fd48510853fc4aee6 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 2 Aug 2018 14:14:24 -0400 Subject: [PATCH 067/105] 3964 - change name of new image to reflect naming schema in 3771 --- Core/build.xml | 2 +- .../src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/build.xml b/Core/build.xml index 322fe961ff..aa654b0f36 100644 --- a/Core/build.xml +++ b/Core/build.xml @@ -86,7 +86,7 @@ - + diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java index 0bb8144527..7af0a429d8 100755 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java @@ -47,7 +47,7 @@ import org.sleuthkit.datamodel.TskCoreException; public class EmbeddedFileTest extends NbTestCase { private static final String CASE_NAME = "EmbeddedFileTest"; - private final Path IMAGE_PATH = Paths.get(this.getDataDir().toString(), "EmbeddedIM_img2_v1.vhd"); + private final Path IMAGE_PATH = Paths.get(this.getDataDir().toString(), "EmbeddedIM_img1_v2.vhd"); public static final String HASH_VALUE = "098f6bcd4621d373cade4e832627b4f6"; private static final int DEEP_FOLDER_COUNT = 25; private Case openCase; From 44849b30a90794ba1fae5d124e743faf6f6a632f Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 2 Aug 2018 14:25:04 -0400 Subject: [PATCH 068/105] Update TableReportGenerator.java --- Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java index ff1479cd86..804696e8db 100644 --- a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java @@ -59,7 +59,7 @@ import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; -class TableReportGenerator { +class TableReportGenerator { private final List artifactTypes = new ArrayList<>(); private final HashSet tagNamesFilter = new HashSet<>(); From 56a713120b6f1b52da6f6accabfedf66516c72a8 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Thu, 2 Aug 2018 15:12:21 -0400 Subject: [PATCH 069/105] Cleanup. --- .../autopsy/directorytree/ExtractAction.java | 115 ++++++++----- .../directorytree/ExtractUnallocAction.java | 151 ++++++++++-------- 2 files changed, 153 insertions(+), 113 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java index 2f45e44331..1f50859bb8 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java @@ -25,7 +25,9 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Set; +import java.util.concurrent.ExecutionException; import java.util.logging.Level; import javax.swing.AbstractAction; import javax.swing.JFileChooser; @@ -33,7 +35,6 @@ import javax.swing.JOptionPane; import javax.swing.SwingWorker; import org.netbeans.api.progress.ProgressHandle; import org.openide.util.Cancellable; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.Utilities; import org.sleuthkit.autopsy.casemodule.Case; @@ -44,8 +45,6 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.autopsy.datamodel.ContentUtils.ExtractFscContentVisitor; import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.TskCoreException; /** * Extracts AbstractFiles to a location selected by the user. @@ -66,6 +65,9 @@ public final class ExtractAction extends AbstractAction { return instance; } + /** + * Private constructor for the action. + */ private ExtractAction() { super(NbBundle.getMessage(ExtractAction.class, "ExtractAction.title.extractFiles.text")); } @@ -94,16 +96,16 @@ public final class ExtractAction extends AbstractAction { /** * Called when user has selected a single file to extract * - * @param e + * @param event * @param selectedFile Selected file */ - @NbBundle.Messages ({"ExtractAction.noOpenCase.errMsg=No open case available."}) - private void extractFile(ActionEvent e, AbstractFile selectedFile) { + @NbBundle.Messages({"ExtractAction.noOpenCase.errMsg=No open case available."}) + private void extractFile(ActionEvent event, AbstractFile selectedFile) { Case openCase; try { openCase = Case.getCurrentCaseThrows(); } catch (NoCurrentCaseException ex) { - JOptionPane.showMessageDialog((Component) e.getSource(), Bundle.ExtractAction_noOpenCase_errMsg()); + JOptionPane.showMessageDialog((Component) event.getSource(), Bundle.ExtractAction_noOpenCase_errMsg()); logger.log(Level.INFO, "Exception while getting open case.", ex); //NON-NLS return; } @@ -111,60 +113,70 @@ public final class ExtractAction extends AbstractAction { fileChooser.setCurrentDirectory(new File(openCase.getExportDirectory())); // If there is an attribute name, change the ":". Otherwise the extracted file will be hidden fileChooser.setSelectedFile(new File(FileUtil.escapeFileName(selectedFile.getName()))); - if (fileChooser.showSaveDialog((Component) e.getSource()) == JFileChooser.APPROVE_OPTION) { + if (fileChooser.showSaveDialog((Component) event.getSource()) == JFileChooser.APPROVE_OPTION) { ArrayList fileExtractionTasks = new ArrayList<>(); fileExtractionTasks.add(new FileExtractionTask(selectedFile, fileChooser.getSelectedFile())); - runExtractionTasks(e, fileExtractionTasks); + runExtractionTasks(event, fileExtractionTasks); } } /** * Called when a user has selected multiple files to extract * - * @param e + * @param event * @param selectedFiles Selected files */ - private void extractFiles(ActionEvent e, Collection selectedFiles) { + private void extractFiles(ActionEvent event, Collection selectedFiles) { Case openCase; try { openCase = Case.getCurrentCaseThrows(); } catch (NoCurrentCaseException ex) { - JOptionPane.showMessageDialog((Component) e.getSource(), Bundle.ExtractAction_noOpenCase_errMsg()); + JOptionPane.showMessageDialog((Component) event.getSource(), Bundle.ExtractAction_noOpenCase_errMsg()); logger.log(Level.INFO, "Exception while getting open case.", ex); //NON-NLS return; } JFileChooser folderChooser = new JFileChooser(); folderChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); folderChooser.setCurrentDirectory(new File(openCase.getExportDirectory())); - if (folderChooser.showSaveDialog((Component) e.getSource()) == JFileChooser.APPROVE_OPTION) { + if (folderChooser.showSaveDialog((Component) event.getSource()) == JFileChooser.APPROVE_OPTION) { File destinationFolder = folderChooser.getSelectedFile(); if (!destinationFolder.exists()) { try { destinationFolder.mkdirs(); } catch (Exception ex) { - JOptionPane.showMessageDialog((Component) e.getSource(), NbBundle.getMessage(this.getClass(), + JOptionPane.showMessageDialog((Component) event.getSource(), NbBundle.getMessage(this.getClass(), "ExtractAction.extractFiles.cantCreateFolderErr.msg")); logger.log(Level.INFO, "Unable to create folder(s) for user " + destinationFolder.getAbsolutePath(), ex); //NON-NLS return; } } - /* get the unique set of files from the list. A user once reported extraction taking - * days because it was extracting the same PST file 20k times. They selected 20k - * email messages in the tree and chose to extract them. */ + /* + * get the unique set of files from the list. A user once reported + * extraction taking days because it was extracting the same PST + * file 20k times. They selected 20k email messages in the tree and + * chose to extract them. + */ Set uniqueFiles = new HashSet<>(selectedFiles); - + // make a task for each file ArrayList fileExtractionTasks = new ArrayList<>(); for (AbstractFile source : uniqueFiles) { // If there is an attribute name, change the ":". Otherwise the extracted file will be hidden fileExtractionTasks.add(new FileExtractionTask(source, new File(destinationFolder, source.getId() + "-" + FileUtil.escapeFileName(source.getName())))); } - runExtractionTasks(e, fileExtractionTasks); + runExtractionTasks(event, fileExtractionTasks); } } - private void runExtractionTasks(ActionEvent e, ArrayList fileExtractionTasks) { + /** + * Execute a series of file extraction tasks. + * + * @param event ActionEvent whose source will be used for + * centering popup dialogs. + * @param fileExtractionTasks List of file extraction tasks. + */ + private void runExtractionTasks(ActionEvent event, List fileExtractionTasks) { // verify all of the sources and destinations are OK for (Iterator it = fileExtractionTasks.iterator(); it.hasNext();) { @@ -177,16 +189,16 @@ public final class ExtractAction extends AbstractAction { } /* - * This code assumes that each destination is unique. We previously satisfied - * that by adding the unique ID. + * This code assumes that each destination is unique. We previously + * satisfied that by adding the unique ID. */ if (task.destination.exists()) { - if (JOptionPane.showConfirmDialog((Component) e.getSource(), + if (JOptionPane.showConfirmDialog((Component) event.getSource(), NbBundle.getMessage(this.getClass(), "ExtractAction.confDlg.destFileExist.msg", task.destination.getAbsolutePath()), NbBundle.getMessage(this.getClass(), "ExtractAction.confDlg.destFileExist.title"), JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { if (!FileUtil.deleteFileDir(task.destination)) { - JOptionPane.showMessageDialog((Component) e.getSource(), + JOptionPane.showMessageDialog((Component) event.getSource(), NbBundle.getMessage(this.getClass(), "ExtractAction.msgDlg.cantOverwriteFile.msg", task.destination.getAbsolutePath())); it.remove(); } @@ -210,11 +222,20 @@ public final class ExtractAction extends AbstractAction { } } + /** + * Stores source and destination for file extraction. + */ private class FileExtractionTask { AbstractFile source; File destination; + /** + * Create an instance of the FileExtractionTask. + * + * @param source The file to be extracted. + * @param destination The destination for the extraction. + */ FileExtractionTask(AbstractFile source, File destination) { this.source = source; this.destination = destination; @@ -226,11 +247,16 @@ public final class ExtractAction extends AbstractAction { */ private class FileExtracter extends SwingWorker { - private Logger logger = Logger.getLogger(FileExtracter.class.getName()); + private final Logger logger = Logger.getLogger(FileExtracter.class.getName()); private ProgressHandle progress; - private ArrayList extractionTasks; + private final List extractionTasks; - FileExtracter(ArrayList extractionTasks) { + /** + * Create an instance of the FileExtracter. + * + * @param extractionTasks List of file extraction tasks. + */ + FileExtracter(List extractionTasks) { this.extractionTasks = extractionTasks; } @@ -275,7 +301,7 @@ public final class ExtractAction extends AbstractAction { boolean msgDisplayed = false; try { super.get(); - } catch (Exception ex) { + } catch (InterruptedException | ExecutionException ex) { logger.log(Level.SEVERE, "Fatal error during file extraction", ex); //NON-NLS MessageNotifyUtil.Message.info( NbBundle.getMessage(this.getClass(), "ExtractAction.done.notifyMsg.extractErr", ex.getMessage())); @@ -289,22 +315,23 @@ public final class ExtractAction extends AbstractAction { } } - private int calculateProgressBarWorkUnits(AbstractFile file) { - int workUnits = 0; - if (file.isFile()) { - workUnits += file.getSize(); - } else { - try { - for (Content child : file.getChildren()) { - if (child instanceof AbstractFile) { - workUnits += calculateProgressBarWorkUnits((AbstractFile) child); - } - } - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Could not get children of content", ex); //NON-NLS - } - } - return workUnits; + /** + * Calculate the number of work units for the progress bar. + * + * @param file File whose children will be reviewed to get the number of + * work units. + * + * @return The number of work units. + */ + /* + * private int calculateProgressBarWorkUnits(AbstractFile file) { int + * workUnits = 0; if (file.isFile()) { workUnits += file.getSize(); } + * else { try { for (Content child : file.getChildren()) { if (child + * instanceof AbstractFile) { workUnits += + * calculateProgressBarWorkUnits((AbstractFile) child); } } } catch + * (TskCoreException ex) { logger.log(Level.SEVERE, "Could not get + * children of content", ex); //NON-NLS } } return workUnits; } + */ } } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java index b0729d24c6..74c7ee1f64 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java @@ -61,6 +61,7 @@ import org.sleuthkit.datamodel.VolumeSystem; * Extracts all the unallocated space as a single file */ final class ExtractUnallocAction extends AbstractAction { + private static final Logger logger = Logger.getLogger(ExtractUnallocAction.class.getName()); private final List filesToExtract = new ArrayList<>(); @@ -69,19 +70,32 @@ final class ExtractUnallocAction extends AbstractAction { private long currentImage = 0L; private final boolean isImage; - public ExtractUnallocAction(String title, Volume volume){ + /** + * Create an instance of ExtractUnallocAction with a volume. + * + * @param title The title + * @param volume The volume set for extraction. + */ + public ExtractUnallocAction(String title, Volume volume) { super(title); isImage = false; try { OutputFileData outputFileData = new OutputFileData(volume); filesToExtract.add(outputFileData); - } catch (NoCurrentCaseException ex) { + } catch (NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Exception while getting open case.", ex); setEnabled(false); } - + } + /** + * Create an instance of ExtractUnallocAction with an image. + * + * @param title The title. + * @param image The image set for extraction. + * @throws NoCurrentCaseException If no case is open. + */ public ExtractUnallocAction(String title, Image image) throws NoCurrentCaseException { super(title); isImage = true; @@ -101,17 +115,17 @@ final class ExtractUnallocAction extends AbstractAction { * Writes the unallocated files to * $CaseDir/Export/ImgName-Unalloc-ImgObjectID-VolumeID.dat * - * @param e + * @param event */ @NbBundle.Messages({"# {0} - fileName", - "ExtractUnallocAction.volumeInProgress=Already extracting unallocated space into {0} - will skip this volume", - "ExtractUnallocAction.volumeError=Error extracting unallocated space from volume", - "ExtractUnallocAction.noFiles=No unallocated files found on volume", - "ExtractUnallocAction.imageError=Error extracting unallocated space from image", - "ExtractUnallocAction.noOpenCase.errMsg=No open case available."}) + "ExtractUnallocAction.volumeInProgress=Already extracting unallocated space into {0} - will skip this volume", + "ExtractUnallocAction.volumeError=Error extracting unallocated space from volume", + "ExtractUnallocAction.noFiles=No unallocated files found on volume", + "ExtractUnallocAction.imageError=Error extracting unallocated space from image", + "ExtractUnallocAction.noOpenCase.errMsg=No open case available."}) @Override - public void actionPerformed(ActionEvent e) { - if (filesToExtract != null && filesToExtract.size() > 0) { + public void actionPerformed(ActionEvent event) { + if (filesToExtract != null && filesToExtract.isEmpty() == false) { // This check doesn't absolutely guarantee that the image won't be in progress when we make the worker, // but in general it will suffice. if (isImage && isImageInProgress(currentImage)) { @@ -150,15 +164,15 @@ final class ExtractUnallocAction extends AbstractAction { NbBundle.getMessage(this.getClass(), "ExtractUnallocAction.dlgTitle.selectDirToSaveTo.msg")); fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); fileChooser.setAcceptAllFileFilterUsed(false); - int returnValue = fileChooser.showSaveDialog((Component) e.getSource()); + int returnValue = fileChooser.showSaveDialog((Component) event.getSource()); if (returnValue == JFileChooser.APPROVE_OPTION) { String destination = fileChooser.getSelectedFile().getPath(); for (OutputFileData outputFileData : filesToExtract) { outputFileData.setPath(destination); - - if (outputFileData.layoutFiles != null && outputFileData.layoutFiles.size() > 0 && (! isVolumeInProgress(outputFileData.getFileName()))) { + + if (outputFileData.layoutFiles != null && outputFileData.layoutFiles.size() > 0 && (!isVolumeInProgress(outputFileData.getFileName()))) { //Format for single Unalloc File is ImgName-Unalloc-ImgObjectID-VolumeID.dat - + // Check if there is already a file with this name if (outputFileData.fileInstance.exists()) { int res = JOptionPane.showConfirmDialog(new Frame(), NbBundle.getMessage(this.getClass(), @@ -172,22 +186,22 @@ final class ExtractUnallocAction extends AbstractAction { copyList.remove(outputFileData); } } - + if (!isImage & !copyList.isEmpty()) { - try{ + try { ExtractUnallocWorker worker = new ExtractUnallocWorker(outputFileData); worker.execute(); - } catch (Exception ex){ - logger.log(Level.WARNING, "Already extracting unallocated space into " + outputFileData.getFileName()); + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "Already extracting unallocated space into {0}", outputFileData.getFileName()); MessageNotifyUtil.Message.info(NbBundle.getMessage(this.getClass(), "ExtractUnallocAction.volumeInProgress", outputFileData.getFileName())); } } } else { // The output file for this volume could not be created for one of the following reasons - if (outputFileData.layoutFiles == null){ + if (outputFileData.layoutFiles == null) { MessageNotifyUtil.Message.info(NbBundle.getMessage(this.getClass(), "ExtractUnallocAction.volumeError")); logger.log(Level.SEVERE, "Tried to get unallocated content but the list of unallocated files was null"); //NON-NLS - } else if (outputFileData.layoutFiles.isEmpty()){ + } else if (outputFileData.layoutFiles.isEmpty()) { MessageNotifyUtil.Message.info(NbBundle.getMessage(this.getClass(), "ExtractUnallocAction.noFiles")); logger.log(Level.WARNING, "No unallocated files found in volume"); //NON-NLS copyList.remove(outputFileData); @@ -198,16 +212,16 @@ final class ExtractUnallocAction extends AbstractAction { } } } - + // This needs refactoring. The idea seems to be that we'll take advantage of the loop above to // check whether each output file exists but wait until this point to make a worker // to extract everything (the worker in the above loop doesn't get created because isImage is true) // It's also unclear to me why we need the two separate worker types. if (isImage && !copyList.isEmpty()) { - try{ + try { ExtractUnallocWorker worker = new ExtractUnallocWorker(copyList); worker.execute(); - } catch (Exception ex){ + } catch (Exception ex) { logger.log(Level.WARNING, "Error creating ExtractUnallocWorker", ex); MessageNotifyUtil.Message.info(NbBundle.getMessage(this.getClass(), "ExtractUnallocAction.imageError")); } @@ -220,16 +234,16 @@ final class ExtractUnallocAction extends AbstractAction { /** * Gets all the unallocated files in a given Content. * - * @param c Content to get Unallocated Files from + * @param content Content to get Unallocated Files from * * @return A list if it didn't crash List may be empty. */ - private List getUnallocFiles(Content c) { - UnallocVisitor uv = new UnallocVisitor(); + private List getUnallocFiles(Content content) { + UnallocVisitor unallocVisitor = new UnallocVisitor(); try { - for (Content contentChild : c.getChildren()) { + for (Content contentChild : content.getChildren()) { if (contentChild instanceof AbstractContent) { - return contentChild.accept(uv); //call on first non-artifact child added to database + return contentChild.accept(unallocVisitor); //call on first non-artifact child added to database } } } catch (TskCoreException tce) { @@ -237,38 +251,37 @@ final class ExtractUnallocAction extends AbstractAction { } return Collections.emptyList(); } - + synchronized static private void addVolumeInProgress(String volumeOutputFileName) throws TskCoreException { - if(volumesInProgress.contains(volumeOutputFileName)){ + if (volumesInProgress.contains(volumeOutputFileName)) { throw new TskCoreException("Already writing unallocated space to " + volumeOutputFileName); - } + } volumesInProgress.add(volumeOutputFileName); } - - synchronized static private void removeVolumeInProgress(String volumeOutputFileName){ + + synchronized static private void removeVolumeInProgress(String volumeOutputFileName) { volumesInProgress.remove(volumeOutputFileName); } - - synchronized static private boolean isVolumeInProgress(String volumeOutputFileName){ + + synchronized static private boolean isVolumeInProgress(String volumeOutputFileName) { return volumesInProgress.contains(volumeOutputFileName); } - - synchronized static private void addImageInProgress(Long id) throws TskCoreException { - if(imagesInProgress.contains(id)){ - throw new TskCoreException("Image " + id + " is in use"); - } - imagesInProgress.add(id); + + synchronized static private void addImageInProgress(Long objId) throws TskCoreException { + if (imagesInProgress.contains(objId)) { + throw new TskCoreException("Image " + objId + " is in use"); + } + imagesInProgress.add(objId); } - - synchronized static private void removeImageInProgress(Long id){ - imagesInProgress.remove(id); - } - - synchronized static private boolean isImageInProgress(Long id){ - return imagesInProgress.contains(id); + + synchronized static private void removeImageInProgress(Long objId) { + imagesInProgress.remove(objId); } - - + + synchronized static private boolean isImageInProgress(Long objId) { + return imagesInProgress.contains(objId); + } + /** * Private class for dispatching the file IO in a background thread. */ @@ -276,9 +289,9 @@ final class ExtractUnallocAction extends AbstractAction { private ProgressHandle progress; private boolean canceled = false; - private List outputFileDataList = new ArrayList<>(); + private final List outputFileDataList = new ArrayList<>(); private File currentlyProcessing; - private int totalSizeinMegs; + private final int totalSizeinMegs; long totalBytes = 0; ExtractUnallocWorker(OutputFileData outputFileData) throws TskCoreException { @@ -291,32 +304,32 @@ final class ExtractUnallocAction extends AbstractAction { ExtractUnallocWorker(List outputFileDataList) throws TskCoreException { addImageInProgress(currentImage); - + //Getting the total megs this worker is going to be doing for (OutputFileData outputFileData : outputFileDataList) { - try{ + try { // If a volume is locked, skip it but continue trying to process any other requested volumes addVolumeInProgress(outputFileData.getFileName()); totalBytes += outputFileData.getSizeInBytes(); this.outputFileDataList.add(outputFileData); - } catch (TskCoreException ex){ - logger.log(Level.WARNING, "Already extracting data into " + outputFileData.getFileName()); + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "Already extracting data into {0}", outputFileData.getFileName()); } } - + // If we don't have anything to output (because of locking), throw an exception - if(this.outputFileDataList.isEmpty()){ + if (this.outputFileDataList.isEmpty()) { throw new TskCoreException("No unallocated files can be extracted"); } - + totalSizeinMegs = toMb(totalBytes); } private int toMb(long bytes) { if (bytes > 1024 && (bytes / 1024.0) <= Double.MAX_VALUE) { - double Mb = ((bytes / 1024.0) / 1024.0);//Bytes -> Megabytes - if (Mb <= Integer.MAX_VALUE) { - return (int) Math.ceil(Mb); + double megabytes = ((bytes / 1024.0) / 1024.0);//Bytes -> Megabytes + if (megabytes <= Integer.MAX_VALUE) { + return (int) Math.ceil(megabytes); } } return 0; @@ -347,7 +360,7 @@ final class ExtractUnallocAction extends AbstractAction { int mbs = 0; //Increments every 128th tick of kbs for (OutputFileData outputFileData : this.outputFileDataList) { currentlyProcessing = outputFileData.getFile(); - logger.log(Level.INFO, "Writing Unalloc file to " + currentlyProcessing.getPath()); //NON-NLS + logger.log(Level.INFO, "Writing Unalloc file to {0}", currentlyProcessing.getPath()); //NON-NLS OutputStream outputStream = new FileOutputStream(currentlyProcessing); long bytes = 0; int i = 0; @@ -374,9 +387,9 @@ final class ExtractUnallocAction extends AbstractAction { if (canceled) { outputFileData.getFile().delete(); - logger.log(Level.INFO, "Canceled extraction of " + outputFileData.getFileName() + " and deleted file"); //NON-NLS + logger.log(Level.INFO, "Canceled extraction of {0} and deleted file", outputFileData.getFileName()); //NON-NLS } else { - logger.log(Level.INFO, "Finished writing unalloc file " + outputFileData.getFile().getPath()); //NON-NLS + logger.log(Level.INFO, "Finished writing unalloc file {0}", outputFileData.getFile().getPath()); //NON-NLS } } progress.finish(); @@ -589,7 +602,7 @@ final class ExtractUnallocAction extends AbstractAction { */ private class OutputFileData { - private List layoutFiles; + private final List layoutFiles; private final long sizeInBytes; private long volumeId; private long imageId; @@ -601,7 +614,7 @@ final class ExtractUnallocAction extends AbstractAction { * Contingency constructor in event no VolumeSystem exists on an Image. * * @param img Image file to be analyzed - * + * * @throws NoCurrentCaseException if there is no open case. */ OutputFileData(Image img) throws NoCurrentCaseException { @@ -619,7 +632,7 @@ final class ExtractUnallocAction extends AbstractAction { * Default constructor for extracting info from Volumes. * * @param volume Volume file to be analyzed - * + * * @throws NoCurrentCaseException if there is no open case. */ OutputFileData(Volume volume) throws NoCurrentCaseException { From 0c571ab20ece0fb87b29e7ca7539f7ea59bd2e14 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Thu, 2 Aug 2018 15:27:27 -0400 Subject: [PATCH 070/105] Added user-defined path for extraction. --- .../autopsy/directorytree/ExtractAction.java | 66 ++++++++++++++++--- .../directorytree/ExtractUnallocAction.java | 44 ++++++++++++- 2 files changed, 99 insertions(+), 11 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java index 2f45e44331..b0b847d1a6 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java @@ -33,7 +33,6 @@ import javax.swing.JOptionPane; import javax.swing.SwingWorker; import org.netbeans.api.progress.ProgressHandle; import org.openide.util.Cancellable; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.Utilities; import org.sleuthkit.autopsy.casemodule.Case; @@ -54,6 +53,8 @@ public final class ExtractAction extends AbstractAction { private Logger logger = Logger.getLogger(ExtractAction.class.getName()); + private String userDefinedExportPath; + // This class is a singleton to support multi-selection of nodes, since // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every // node in the array returns a reference to the same action object from Node.getActions(boolean). @@ -97,7 +98,7 @@ public final class ExtractAction extends AbstractAction { * @param e * @param selectedFile Selected file */ - @NbBundle.Messages ({"ExtractAction.noOpenCase.errMsg=No open case available."}) + @NbBundle.Messages({"ExtractAction.noOpenCase.errMsg=No open case available."}) private void extractFile(ActionEvent e, AbstractFile selectedFile) { Case openCase; try { @@ -108,10 +109,12 @@ public final class ExtractAction extends AbstractAction { return; } JFileChooser fileChooser = new JFileChooser(); - fileChooser.setCurrentDirectory(new File(openCase.getExportDirectory())); + fileChooser.setCurrentDirectory(new File(getExportDirectory(openCase))); // If there is an attribute name, change the ":". Otherwise the extracted file will be hidden fileChooser.setSelectedFile(new File(FileUtil.escapeFileName(selectedFile.getName()))); if (fileChooser.showSaveDialog((Component) e.getSource()) == JFileChooser.APPROVE_OPTION) { + updateExportDirectory(fileChooser.getSelectedFile().getParent(), openCase); + ArrayList fileExtractionTasks = new ArrayList<>(); fileExtractionTasks.add(new FileExtractionTask(selectedFile, fileChooser.getSelectedFile())); runExtractionTasks(e, fileExtractionTasks); @@ -135,7 +138,7 @@ public final class ExtractAction extends AbstractAction { } JFileChooser folderChooser = new JFileChooser(); folderChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - folderChooser.setCurrentDirectory(new File(openCase.getExportDirectory())); + folderChooser.setCurrentDirectory(new File(getExportDirectory(openCase))); if (folderChooser.showSaveDialog((Component) e.getSource()) == JFileChooser.APPROVE_OPTION) { File destinationFolder = folderChooser.getSelectedFile(); if (!destinationFolder.exists()) { @@ -148,12 +151,16 @@ public final class ExtractAction extends AbstractAction { return; } } + updateExportDirectory(destinationFolder.getPath(), openCase); - /* get the unique set of files from the list. A user once reported extraction taking - * days because it was extracting the same PST file 20k times. They selected 20k - * email messages in the tree and chose to extract them. */ + /* + * get the unique set of files from the list. A user once reported + * extraction taking days because it was extracting the same PST + * file 20k times. They selected 20k email messages in the tree and + * chose to extract them. + */ Set uniqueFiles = new HashSet<>(selectedFiles); - + // make a task for each file ArrayList fileExtractionTasks = new ArrayList<>(); for (AbstractFile source : uniqueFiles) { @@ -164,6 +171,45 @@ public final class ExtractAction extends AbstractAction { } } + /** + * Get the export directory path. + * + * @param openCase The current case. + * + * @return The export directory path. + */ + private String getExportDirectory(Case openCase) { + String caseExportPath = openCase.getExportDirectory(); + + if (userDefinedExportPath == null) { + return caseExportPath; + } + + File file = new File(userDefinedExportPath); + if (file.exists() == false || file.isDirectory() == false) { + return caseExportPath; + } + + return userDefinedExportPath; + } + + /** + * Update the default export directory. If the directory path matches the + * case export directory, then the directory used will always match the + * export directory of any given case. Otherwise, the path last used will be + * saved. + * + * @param exportPath The export path. + * @param openCase The current case. + */ + private void updateExportDirectory(String exportPath, Case openCase) { + if (exportPath.equalsIgnoreCase(openCase.getExportDirectory())) { + userDefinedExportPath = null; + } else { + userDefinedExportPath = exportPath; + } + } + private void runExtractionTasks(ActionEvent e, ArrayList fileExtractionTasks) { // verify all of the sources and destinations are OK @@ -177,8 +223,8 @@ public final class ExtractAction extends AbstractAction { } /* - * This code assumes that each destination is unique. We previously satisfied - * that by adding the unique ID. + * This code assumes that each destination is unique. We previously + * satisfied that by adding the unique ID. */ if (task.destination.exists()) { if (JOptionPane.showConfirmDialog((Component) e.getSource(), diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java index b0729d24c6..83fe882e45 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java @@ -66,6 +66,7 @@ final class ExtractUnallocAction extends AbstractAction { private final List filesToExtract = new ArrayList<>(); private static final Set volumesInProgress = new HashSet<>(); private static final Set imagesInProgress = new HashSet<>(); + private static String userDefinedExportPath; private long currentImage = 0L; private final boolean isImage; @@ -145,7 +146,7 @@ final class ExtractUnallocAction extends AbstractAction { } }; - fileChooser.setCurrentDirectory(new File(openCase.getExportDirectory())); + fileChooser.setCurrentDirectory(new File(getExportDirectory(openCase))); fileChooser.setDialogTitle( NbBundle.getMessage(this.getClass(), "ExtractUnallocAction.dlgTitle.selectDirToSaveTo.msg")); fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); @@ -153,6 +154,9 @@ final class ExtractUnallocAction extends AbstractAction { int returnValue = fileChooser.showSaveDialog((Component) e.getSource()); if (returnValue == JFileChooser.APPROVE_OPTION) { String destination = fileChooser.getSelectedFile().getPath(); + + updateExportDirectory(destination, openCase); + for (OutputFileData outputFileData : filesToExtract) { outputFileData.setPath(destination); @@ -214,7 +218,45 @@ final class ExtractUnallocAction extends AbstractAction { } } } + } + + /** + * Get the export directory path. + * + * @param openCase The current case. + * + * @return The export directory path. + */ + private String getExportDirectory(Case openCase) { + String caseExportPath = openCase.getExportDirectory(); + if (userDefinedExportPath == null) { + return caseExportPath; + } + + File file = new File(userDefinedExportPath); + if (file.exists() == false || file.isDirectory() == false) { + return caseExportPath; + } + + return userDefinedExportPath; + } + + /** + * Update the default export directory. If the directory path matches the + * case export directory, then the directory used will always match the + * export directory of any given case. Otherwise, the path last used will be + * saved. + * + * @param exportPath The export path. + * @param openCase The current case. + */ + private void updateExportDirectory(String exportPath, Case openCase) { + if (exportPath.equalsIgnoreCase(openCase.getExportDirectory())) { + userDefinedExportPath = null; + } else { + userDefinedExportPath = exportPath; + } } /** From 21fc9a67a952300e4b2bd556ce42b175540da706 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 2 Aug 2018 16:08:21 -0400 Subject: [PATCH 071/105] 3964 adjust failure messages for zip bomb test to give more context --- .../autopsy/ingest/EmbeddedFileTest.java | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java index 7af0a429d8..995aac1818 100755 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java @@ -96,43 +96,45 @@ public class EmbeddedFileTest extends NbTestCase { public void testEncryptionAndZipBomb() { try { - List results = openCase.getSleuthkitCase().findAllFilesWhere("name LIKE '%%'"); - String protectedName1 = "password_protected.zip"; - String protectedName2 = "level1_protected.zip"; - String protectedName3 = "42.zip"; - String depthZipBomb = "DepthTriggerZipBomb.zip"; - String ratioZipBomb = "RatioTriggerZipBomb.zip"; + List results = openCase.getSleuthkitCase().findAllFilesWhere("name LIKE '%%'"); + final String zipBombSetName = "Possible Zip Bomb"; + final String protectedName1 = "password_protected.zip"; + final String protectedName2 = "level1_protected.zip"; + final String protectedName3 = "42.zip"; + final String depthZipBomb = "DepthTriggerZipBomb.zip"; + final String ratioZipBomb = "RatioTriggerZipBomb.zip"; int zipBombs = 0; - assertEquals(2221, results.size()); + assertEquals("The number of files in the test image has changed", 2221, results.size()); int passwdProtectedZips = 0; for (AbstractFile file : results) { //.zip file has artifact TSK_ENCRYPTION_DETECTED if (file.getName().equalsIgnoreCase(protectedName1) || file.getName().equalsIgnoreCase(protectedName2) || file.getName().equalsIgnoreCase(protectedName3)){ ArrayList artifacts = file.getAllArtifacts(); - assertEquals(1, artifacts.size()); + assertEquals("Password protected zip file " + file.getName() + " has incorrect number of artifacts", 1, artifacts.size()); for (BlackboardArtifact artifact : artifacts) { - assertEquals(artifact.getArtifactTypeID(), BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID()); + assertEquals("Artifact for password protected zip file " + file.getName() + " has incorrect type ID", artifact.getArtifactTypeID(), BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID()); passwdProtectedZips++; } } else if (file.getName().equalsIgnoreCase(depthZipBomb) || file.getName().equalsIgnoreCase(ratioZipBomb)){ ArrayList artifacts = file.getAllArtifacts(); - assertEquals(1, artifacts.size()); + assertEquals("Zip bomb " + file.getName() + " has incorrect number of artifacts", 1, artifacts.size()); for (BlackboardArtifact artifact : artifacts) { - assertEquals(artifact.getArtifactTypeID(), BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID()); + assertEquals("Artifact for Zip bomb " + file.getName() + " has incorrect type ID", artifact.getArtifactTypeID(), BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID()); BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME)); - assertNotNull("Possible Zip Bomb", attribute); + assertNotNull("No attribute found for artifact on zip bomb " + file.getName(), attribute); + assertEquals("Interesting artifact on file, " + file.getName() + ", does not reflect it being a zip bomb", zipBombSetName, attribute.getDisplayString()); zipBombs++; } } else {//No other files have artifact defined - assertEquals(0, file.getAllArtifacts().size()); + assertEquals("Unexpected file, " + file.getName() + ", has artifacts", 0, file.getAllArtifacts().size()); } } //Make sure 3 password protected zip files have been tested: password_protected.zip, level1_protected.zip and 42.zip that we download for bomb testing. - assertEquals(3, passwdProtectedZips); + assertEquals("Unexpected number of artifacts reflecting password protected zip files found", 3, passwdProtectedZips); //Make sure 2 zip bomb files have been tested: DepthTriggerZipBomb.zip and RatioTriggerZipBomb.zip. - assertEquals(2, zipBombs); + assertEquals("Unexpected number of artifacts reflecting zip bombs found", 2, zipBombs); } catch (TskCoreException ex) { Exceptions.printStackTrace(ex); Assert.fail(ex); From 7b371dc1251c6c308e27d3760206708ecda8114f Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Thu, 2 Aug 2018 16:45:35 -0400 Subject: [PATCH 072/105] Refactored names and comments --- .../SevenZipExtractor.java | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java index ca1dd28233..234275c41d 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java @@ -469,7 +469,6 @@ class SevenZipExtractor { boolean hasEncrypted = false; boolean fullEncryption = true; boolean progressStarted = false; - int processedItems = 0; final String archiveFilePath = getArchiveFilePath(archiveFile); final String escapedArchiveFilePath = FileUtil.escapeFileName(archiveFilePath); HashMap statusMap = new HashMap<>(); @@ -651,7 +650,7 @@ class SevenZipExtractor { unpackedNode, localAbsPath, localRelPath)); } - int[] extractionIndices = getExtractableFilesFromArchiveDetails(archiveDetailsMap); + int[] extractionIndices = getExtractableFilesFromDetailsMap(archiveDetailsMap); StandardIArchiveExtractCallback archiveCallBack = new StandardIArchiveExtractCallback( @@ -768,7 +767,7 @@ class SevenZipExtractor { * Produce a list of archive indices needed for the call to extract, which * will open the archive and begin unpacking the files. */ - private int[] getExtractableFilesFromArchiveDetails( + private int[] getExtractableFilesFromDetailsMap( Map archiveDetailsMap) { Integer[] wrappedExtractionIndices = archiveDetailsMap.keySet() @@ -950,19 +949,20 @@ class SevenZipExtractor { private static class StandardIArchiveExtractCallback implements IArchiveExtractCallback, ICryptoGetTextPassword { - private int inArchiveItemIndex; + private AbstractFile archiveFile; private ISevenZipInArchive inArchive; private SevenZipExtractor.UnpackStream unpackStream = null; - private long freeDiskSpace; private Map archiveDetailsMap; private ProgressHandle progressHandle; - private AbstractFile archiveFile; + + private int inArchiveItemIndex; + private long freeDiskSpace; private long createTimeInSeconds; private long modTimeInSeconds; private long accessTimeInSeconds; - private boolean skipExtraction; + private boolean isFolder; private String password; private boolean unpackSuccessful = true; @@ -981,14 +981,14 @@ class SevenZipExtractor { } @Override - public ISequentialOutStream getStream( - int i, ExtractAskMode EAM) throws SevenZipException { + public ISequentialOutStream getStream(int inArchiveItemIndex, + ExtractAskMode mode) throws SevenZipException { - inArchiveItemIndex = i; + this.inArchiveItemIndex = inArchiveItemIndex; - skipExtraction = (Boolean) inArchive + isFolder = (Boolean) inArchive .getProperty(inArchiveItemIndex, PropID.IS_FOLDER); - if (skipExtraction || EAM != ExtractAskMode.EXTRACT) { + if (isFolder || mode != ExtractAskMode.EXTRACT) { return null; } @@ -1009,7 +1009,7 @@ class SevenZipExtractor { } @Override - public void prepareOperation(ExtractAskMode eam) throws SevenZipException { + public void prepareOperation(ExtractAskMode mode) throws SevenZipException { final Date createTime = (Date) inArchive.getProperty( inArchiveItemIndex, PropID.CREATION_TIME); final Date accessTime = (Date) inArchive.getProperty( @@ -1035,7 +1035,7 @@ class SevenZipExtractor { * @throws SevenZipException */ @Override - public void setOperationResult(ExtractOperationResult EOR) throws SevenZipException { + public void setOperationResult(ExtractOperationResult result) throws SevenZipException { final SevenZipExtractor.UnpackedTree.UnpackedNode unpackedNode = archiveDetailsMap.get(inArchiveItemIndex).getUnpackedNode(); final String localRelPath = archiveDetailsMap.get( @@ -1047,7 +1047,7 @@ class SevenZipExtractor { + (String) inArchive.getProperty(inArchiveItemIndex, PropID.PATH), inArchiveItemIndex); - if (skipExtraction) { + if (isFolder) { unpackedNode.addDerivedInfo(0, !(Boolean) inArchive.getProperty(inArchiveItemIndex, PropID.IS_FOLDER), 0L, createTimeInSeconds, accessTimeInSeconds, modTimeInSeconds, @@ -1055,10 +1055,9 @@ class SevenZipExtractor { return; } - //TODO - causes unpack to be unsuccessful, implement fix. - if (EOR != ExtractOperationResult.OK) { + if (result != ExtractOperationResult.OK) { logger.log(Level.WARNING, "Extraction of : {0} encountered error {1}", //NON-NLS - new Object[]{localAbsPath, EOR}); + new Object[]{localAbsPath, result}); unpackSuccessful = false; } From 7c62e2461536fd5145721c20555b7277967277c3 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Thu, 2 Aug 2018 17:06:45 -0400 Subject: [PATCH 073/105] Refactored package name and class name --- .../SQLiteExtractor.java => sqlitereader/SQLiteReader.java} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Core/src/org/sleuthkit/autopsy/{textextraction/SQLiteExtractor.java => sqlitereader/SQLiteReader.java} (100%) diff --git a/Core/src/org/sleuthkit/autopsy/textextraction/SQLiteExtractor.java b/Core/src/org/sleuthkit/autopsy/sqlitereader/SQLiteReader.java similarity index 100% rename from Core/src/org/sleuthkit/autopsy/textextraction/SQLiteExtractor.java rename to Core/src/org/sleuthkit/autopsy/sqlitereader/SQLiteReader.java From 2c453f0b76b23f867bdbb4b7d71430f793277406 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Thu, 2 Aug 2018 17:17:24 -0400 Subject: [PATCH 074/105] Refactored package and class name --- .../autopsy/contentviewers/SQLiteViewer.java | 14 +++++++------- .../autopsy/sqlitereader/SQLiteReader.java | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java index aaaf0a368a..eb07dfd271 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java @@ -47,7 +47,7 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.datamodel.ContentUtils; -import org.sleuthkit.autopsy.textextraction.SQLiteExtractor; +import org.sleuthkit.autopsy.sqlitereader.SQLiteReader; import org.sleuthkit.datamodel.SleuthkitCase; /** @@ -371,8 +371,8 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { File.separator + sqliteDbFile.getName(); moveDbToTempFile(sqliteDbFile, tmpDBPathName); - connection = SQLiteExtractor.getDatabaseConnection(tmpDBPathName); - Map dbTablesMap = SQLiteExtractor.getTableNameAndSchemaPairs(connection); + connection = SQLiteReader.getDatabaseConnection(tmpDBPathName); + Map dbTablesMap = SQLiteReader.getTableNameAndSchemaPairs(connection); if (dbTablesMap.isEmpty()) { tablesDropdownList.addItem(Bundle.SQLiteViewer_comboBox_noTableEntry()); @@ -411,7 +411,7 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { }) private void selectTable(String tableName) { try { - numRows = SQLiteExtractor.getTableRowCount(connection, tableName); + numRows = SQLiteReader.getTableRowCount(connection, tableName); numEntriesField.setText(numRows + " entries"); currPage = 1; @@ -444,7 +444,7 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { private void readTable(String tableName, int startRow, int numRowsToRead) { try { - List> rows = SQLiteExtractor.getRowsFromTable( + List> rows = SQLiteReader.getRowsFromTable( connection, tableName, startRow, numRowsToRead); if (Objects.nonNull(rows)) { selectedTableView.setupTable(rows); @@ -468,14 +468,14 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { String tableName = (String) this.tablesDropdownList.getSelectedItem(); try { List> currentTableRows = - SQLiteExtractor.getRowsFromTable(connection, tableName); + SQLiteReader.getRowsFromTable(connection, tableName); if (Objects.isNull(currentTableRows) || currentTableRows.isEmpty()) { logger.log(Level.INFO, String.format( "The table %s is empty. (objId=%d)", tableName, //NON-NLS sqliteDbFile.getId())); } else { - SQLiteExtractor.exportTableToCSV(file, tableName, currentTableRows); + SQLiteReader.exportTableToCSV(file, tableName, currentTableRows); } } catch (SQLException ex) { logger.log(Level.SEVERE, String.format( diff --git a/Core/src/org/sleuthkit/autopsy/sqlitereader/SQLiteReader.java b/Core/src/org/sleuthkit/autopsy/sqlitereader/SQLiteReader.java index a3966c76c5..90a63ad0eb 100755 --- a/Core/src/org/sleuthkit/autopsy/sqlitereader/SQLiteReader.java +++ b/Core/src/org/sleuthkit/autopsy/sqlitereader/SQLiteReader.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.textextraction; +package org.sleuthkit.autopsy.sqlitereader; import java.io.File; import java.io.FileNotFoundException; @@ -42,9 +42,9 @@ import org.openide.util.NbBundle; * JDBC. Classes using the SQLiteExtractor must maintain a reference to the * Connection object generated in getDatabaseConnection. */ -public final class SQLiteExtractor { +public final class SQLiteReader { - private SQLiteExtractor(){} + private SQLiteReader(){} public static Connection getDatabaseConnection(String dbPath) throws ClassNotFoundException, SQLException { From 5238b6b5dd2527e7cf172cad06abba91084905d3 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Thu, 2 Aug 2018 17:50:26 -0400 Subject: [PATCH 075/105] Fixed dialog size. --- .../centralrepository/Bundle.properties | 2 - .../CentralRepoCommentDialog.form | 42 ++++--------------- .../CentralRepoCommentDialog.java | 26 ++---------- 3 files changed, 12 insertions(+), 58 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/Bundle.properties b/Core/src/org/sleuthkit/autopsy/centralrepository/Bundle.properties index 3223583037..1c7e6c2d7e 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/Bundle.properties @@ -5,8 +5,6 @@ OpenIDE-Module-Long-Description=\ Correlation Engine ingest module and central database. \n\n\ The Correlation Engine ingest module stores attributes of artifacts matching selected correlation types into a central database.\n\ Stored attributes are used in future cases to correlate and analyzes files and artifacts during ingest. -CentralRepoCommentDialog.fileLabel.text=File: CentralRepoCommentDialog.commentLabel.text=Comment: -CentralRepoCommentDialog.pathLabel.text= CentralRepoCommentDialog.okButton.text=&OK CentralRepoCommentDialog.cancelButton.text=C&ancel diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.form b/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.form index 5a9882d4cf..8f471230d0 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.form +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.form @@ -31,14 +31,7 @@ - - - - - - - - + @@ -55,21 +48,16 @@ - - - - - - + - + - - - - + + + + - + @@ -113,20 +101,6 @@ - - - - - - - - - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.java b/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.java index 529ffb8529..5325c0fc2f 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.java @@ -52,7 +52,6 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog { currentComment = instance.getComment(); } - pathLabel.setText(instance.getFilePath()); commentTextArea.setText(instance.getComment()); this.correlationAttribute = correlationAttribute; @@ -103,8 +102,6 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog { commentTextArea = new javax.swing.JTextArea(); okButton = new javax.swing.JButton(); cancelButton = new javax.swing.JButton(); - fileLabel = new javax.swing.JLabel(); - pathLabel = new javax.swing.JLabel(); commentLabel = new javax.swing.JLabel(); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); @@ -131,10 +128,6 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog { } }); - org.openide.awt.Mnemonics.setLocalizedText(fileLabel, org.openide.util.NbBundle.getMessage(CentralRepoCommentDialog.class, "CentralRepoCommentDialog.fileLabel.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(pathLabel, org.openide.util.NbBundle.getMessage(CentralRepoCommentDialog.class, "CentralRepoCommentDialog.pathLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(commentLabel, org.openide.util.NbBundle.getMessage(CentralRepoCommentDialog.class, "CentralRepoCommentDialog.commentLabel.text")); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); @@ -146,12 +139,7 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog { .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 500, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(fileLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(pathLabel)) - .addComponent(commentLabel)) + .addComponent(commentLabel) .addGap(0, 451, Short.MAX_VALUE)) .addGroup(layout.createSequentialGroup() .addGap(0, 0, Short.MAX_VALUE) @@ -164,17 +152,13 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog { layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(fileLabel) - .addComponent(pathLabel)) - .addGap(19, 19, 19) .addComponent(commentLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jScrollPane1) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(okButton) - .addComponent(cancelButton)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(cancelButton) + .addComponent(okButton)) .addContainerGap()) ); @@ -197,9 +181,7 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog { private javax.swing.JButton cancelButton; private javax.swing.JLabel commentLabel; private javax.swing.JTextArea commentTextArea; - private javax.swing.JLabel fileLabel; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JButton okButton; - private javax.swing.JLabel pathLabel; // End of variables declaration//GEN-END:variables } From 372ca76864d6d1fac73d3fa1f6e43fd9e26eacad Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 24 Jul 2018 14:52:53 -0400 Subject: [PATCH 076/105] 4065 initial implementation without refresh - minimal public api changes --- .../casemodule/services/TagsManager.java | 112 ++++++++++++++---- .../autopsy/core/UserPreferences.java | 17 ++- .../org/sleuthkit/autopsy/datamodel/Tags.java | 94 +++++++++------ .../autopsy/directorytree/Bundle.properties | 3 +- .../DirectoryTreeTopComponent.form | 19 ++- .../DirectoryTreeTopComponent.java | 22 +++- 6 files changed, 199 insertions(+), 68 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index d80feed87a..786e461619 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -30,6 +30,7 @@ import java.util.logging.Level; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifactTag; @@ -71,13 +72,14 @@ public class TagsManager implements Closeable { || tagDisplayName.contains(";")); } + @NbBundle.Messages({"TagsManager.notableTagEnding.text= (Notable)"}) /** - * Get String of text which is used to label tags as notable to the user. - * + * Get String of text which is used to label tags as notable to the user. + * * @return Bundle message TagsManager.notableTagEnding.text */ - public static String getNotableTagLabel(){ + public static String getNotableTagLabel() { return Bundle.TagsManager_notableTagEnding_text(); } @@ -123,13 +125,13 @@ public class TagsManager implements Closeable { /** * Returns a list of names of standard/predefined tags - * + * * @return list of predefined tag names */ public static List getStandardTagNames() { return TagNameDefinition.getStandardTagNames(); } - + /** * Constructs a per case Autopsy service that manages the addition of * content and artifact tags to the case database. @@ -163,7 +165,26 @@ public class TagsManager implements Closeable { * @throws TskCoreException If there is an error querying the case database. */ public List getTagNamesInUse() throws TskCoreException { - return caseDb.getTagNamesInUse(); + if (UserPreferences.showOnlyCurrentUserTags()) { +// return caseDb.getTagNamesInUse(System.getProperty("user.name")); + Set tagNameSet = new HashSet<>(); + String userName = System.getProperty("user.name"); + List artifactTags = caseDb.getAllBlackboardArtifactTags(); + for (BlackboardArtifactTag tag : artifactTags) { + if (tag.getUserName().equals(userName)) { + tagNameSet.add(tag.getName()); + } + } + List contentTags = caseDb.getAllContentTags(); + for (ContentTag tag : contentTags) { + if (tag.getUserName().equals(userName)) { + tagNameSet.add(tag.getName()); + } + } + return new ArrayList(tagNameSet); + } else { + return caseDb.getTagNamesInUse(); + } } /** @@ -172,15 +193,35 @@ public class TagsManager implements Closeable { * blackboard_artifact_tags tables, for the given data source object id. * * @param dsObjId data source object id - * + * * @return A list, possibly empty, of TagName data transfer objects (DTOs) - * for the rows. + * for the rows. * * @throws TskCoreException */ public List getTagNamesInUse(long dsObjId) throws TskCoreException { - return caseDb.getTagNamesInUse(dsObjId); + if (UserPreferences.showOnlyCurrentUserTags()) { +// return caseDb.getTagNamesInUse(dsObjId, System.getProperty("user.name")); + Set tagNameSet = new HashSet<>(); + String userName = System.getProperty("user.name"); + List artifactTags = caseDb.getAllBlackboardArtifactTags(); + for (BlackboardArtifactTag tag : artifactTags) { + if (tag.getUserName().equals(userName) && tag.getArtifact().getDataSource().getId() == dsObjId) { + tagNameSet.add(tag.getName()); + } + } + List contentTags = caseDb.getAllContentTags(); + for (ContentTag tag : contentTags) { + if (tag.getUserName().equals(userName) && tag.getContent().getDataSource().getId() == dsObjId) { + tagNameSet.add(tag.getName()); + } + } + return new ArrayList(tagNameSet); + } else { + return caseDb.getTagNamesInUse(dsObjId); + } } + /** * Gets a map of tag display names to tag name entries in the case database. * It has keys for the display names of the standard tag types, the current @@ -413,27 +454,52 @@ public class TagsManager implements Closeable { * the case database. */ public long getContentTagsCountByTagName(TagName tagName) throws TskCoreException { - return caseDb.getContentTagsCountByTagName(tagName); + if (UserPreferences.showOnlyCurrentUserTags()) { + String userName = System.getProperty("user.name"); + long count = 0; + List contentTags = getContentTagsByTagName(tagName); + for (ContentTag tag : contentTags) { + if (userName.equals(tag.getUserName())) { + count++; + } + } + return count; + } else { + return caseDb.getContentTagsCountByTagName(tagName); + } } /** * Gets content tags count by tag name, for the given data source * * @param tagName The representation of the desired tag type in the case - * database, which can be obtained by calling getTagNames and/or addTagName. - * + * database, which can be obtained by calling getTagNames + * and/or addTagName. + * * @param dsObjId data source object id * * @return A count of the content tags with the specified tag name, and for - * the given data source + * the given data source * * @throws TskCoreException If there is an error getting the tags count from - * the case database. + * the case database. */ public long getContentTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException { - return caseDb.getContentTagsCountByTagName(tagName, dsObjId); + if (UserPreferences.showOnlyCurrentUserTags()) { + String userName = System.getProperty("user.name"); + long count = 0; + List contentTags = getContentTagsByTagName(tagName, dsObjId); + for (ContentTag tag : contentTags) { + if (userName.equals(tag.getUserName())) { + count++; + } + } + return count; + } else { + return caseDb.getContentTagsCountByTagName(tagName, dsObjId); + } } - + /** * Gets a content tag by tag id. * @@ -463,11 +529,11 @@ public class TagsManager implements Closeable { return caseDb.getContentTagsByTagName(tagName); } - /** + /** * Gets content tags by tag name, for the given data source. * * @param tagName The tag name of interest. - * + * * @param dsObjId data source object id * * @return A list, possibly empty, of the content tags with the specified @@ -479,7 +545,7 @@ public class TagsManager implements Closeable { public List getContentTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException { return caseDb.getContentTagsByTagName(tagName, dsObjId); } - + /** * Gets content tags count by content. * @@ -589,8 +655,8 @@ public class TagsManager implements Closeable { * and/or addTagName. * @param dsObjId data source object id * - * @return A count of the artifact tags with the specified tag name, - * for the given data source. + * @return A count of the artifact tags with the specified tag name, for the + * given data source. * * @throws TskCoreException If there is an error getting the tags count from * the case database. @@ -598,7 +664,7 @@ public class TagsManager implements Closeable { public long getBlackboardArtifactTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException { return caseDb.getBlackboardArtifactTagsCountByTagName(tagName, dsObjId); } - + /** * Gets an artifact tag by tag id. * @@ -647,7 +713,7 @@ public class TagsManager implements Closeable { public List getBlackboardArtifactTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException { return caseDb.getBlackboardArtifactTagsByTagName(tagName, dsObjId); } - + /** * Gets artifact tags for a particular artifact. * diff --git a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java index 22fa2b7135..9869001067 100644 --- a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java +++ b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java @@ -70,7 +70,8 @@ public final class UserPreferences { private static final String MAX_NUM_OF_LOG_FILE = "MaximumNumberOfLogFiles"; private static final int LOG_FILE_NUM_INT = 10; public static final String GROUP_ITEMS_IN_TREE_BY_DATASOURCE = "GroupItemsInTreeByDataSource"; //NON-NLS - + private static final String SHOW_ONLY_CURRENT_USER_TAGS = "ShowOnlyCurrentUserTags"; + // Prevent instantiation. private UserPreferences() { } @@ -196,6 +197,14 @@ public final class UserPreferences { preferences.putBoolean(GROUP_ITEMS_IN_TREE_BY_DATASOURCE, value); } + public static boolean showOnlyCurrentUserTags() { + return preferences.getBoolean(SHOW_ONLY_CURRENT_USER_TAGS, false); + } + + public static void setShowOnlyCurrentUserTags(boolean value) { + preferences.putBoolean(SHOW_ONLY_CURRENT_USER_TAGS, value); + } + /** * Reads persisted case database connection info. * @@ -379,21 +388,25 @@ public final class UserPreferences { /** * get the maximum number of log files to save + * * @return Number of log files */ public static int getLogFileCount() { return preferences.getInt(MAX_NUM_OF_LOG_FILE, LOG_FILE_NUM_INT); } - + /** * get the default number of log files to save + * * @return LOG_FILE_COUNT */ public static int getDefaultLogFileCount() { return LOG_FILE_NUM_INT; } + /** * Set the maximum number of log files to save + * * @param count number of log files */ public static void setLogFileCount(int count) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index c41a750f7e..643f3ecda6 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -1,15 +1,15 @@ /* * Autopsy Forensic Browser - * + * * Copyright 2011-2018 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. @@ -59,19 +59,19 @@ public class Tags implements AutopsyVisitableItem { private final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS private final long datasourceObjId; - + Tags() { - this(0); + this(0); } - + Tags(long dsObjId) { this.datasourceObjId = dsObjId; } - + long filteringDataSourceObjId() { return this.datasourceObjId; } - + @Override public T accept(AutopsyItemVisitor visitor) { return visitor.visit(this); @@ -98,13 +98,12 @@ public class Tags implements AutopsyVisitableItem { */ public class RootNode extends DisplayableItemNode { - public RootNode(long objId) { super(Children.create(new TagNameNodeFactory(objId), true), Lookups.singleton(DISPLAY_NAME)); super.setName(DISPLAY_NAME); super.setDisplayName(DISPLAY_NAME); this.setIconBaseWithExtension(ICON_PATH); - + } @Override @@ -139,7 +138,7 @@ public class Tags implements AutopsyVisitableItem { private class TagNameNodeFactory extends ChildFactory.Detachable implements Observer { private final long datasourceObjId; - + private final Set CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED, Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED, Case.Events.CONTENT_TAG_ADDED, @@ -197,13 +196,14 @@ public class Tags implements AutopsyVisitableItem { /** * Constructor + * * @param objId data source object id */ TagNameNodeFactory(long objId) { this.datasourceObjId = objId; - + } - + @Override protected void addNotify() { IngestManager.getInstance().addIngestJobEventListener(pcl); @@ -224,11 +224,10 @@ public class Tags implements AutopsyVisitableItem { @Override protected boolean createKeys(List keys) { try { - - List tagNamesInUse = UserPreferences.groupItemsInTreeByDatasource() ? - Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse(datasourceObjId) : - Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse() - ; + + List tagNamesInUse = UserPreferences.groupItemsInTreeByDatasource() + ? Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse(datasourceObjId) + : Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse(); Collections.sort(tagNamesInUse); keys.addAll(tagNamesInUse); } catch (TskCoreException | NoCurrentCaseException ex) { @@ -277,14 +276,13 @@ public class Tags implements AutopsyVisitableItem { try { TagsManager tm = Case.getCurrentCaseThrows().getServices().getTagsManager(); if (UserPreferences.groupItemsInTreeByDatasource()) { - tagsCount = tm.getContentTagsCountByTagName(tagName, datasourceObjId); + tagsCount = tm.getContentTagsCountByTagName(tagName, datasourceObjId); tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName, datasourceObjId); - } - else { + } else { tagsCount = tm.getContentTagsCountByTagName(tagName); tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName); } - + } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(TagNameNode.class.getName()).log(Level.SEVERE, "Failed to get tags count for " + tagName.getDisplayName() + " tag name", ex); //NON-NLS } @@ -387,9 +385,9 @@ public class Tags implements AutopsyVisitableItem { private void updateDisplayName() { long tagsCount = 0; try { - tagsCount = UserPreferences.groupItemsInTreeByDatasource() ? - Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName, datasourceObjId) : - Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName); + tagsCount = UserPreferences.groupItemsInTreeByDatasource() + ? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName, datasourceObjId) + : Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName); } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(ContentTagTypeNode.class.getName()).log(Level.SEVERE, "Failed to get content tags count for " + tagName.getDisplayName() + " tag name", ex); //NON-NLS } @@ -444,11 +442,20 @@ public class Tags implements AutopsyVisitableItem { protected boolean createKeys(List keys) { // Use the content tags bearing the specified tag name as the keys. try { - List contentTags = UserPreferences.groupItemsInTreeByDatasource() ? - Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName, datasourceObjId) : - Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName); - - keys.addAll(contentTags); + List contentTags = UserPreferences.groupItemsInTreeByDatasource() + ? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName, datasourceObjId) + : Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName); + if (UserPreferences.showOnlyCurrentUserTags()) { + String userName = System.getProperty("user.name"); + for (ContentTag tag : contentTags){ + if (userName.equals(tag.getUserName())){ + keys.add(tag); + } + } + } + else { + keys.addAll(contentTags); + } } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(ContentTagNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS } @@ -479,6 +486,7 @@ public class Tags implements AutopsyVisitableItem { private final TagName tagName; private final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS + private int displayCount = 0; public BlackboardArtifactTagTypeNode(TagName tagName) { super(Children.create(new BlackboardArtifactTagNodeFactory(tagName), true), Lookups.singleton(tagName.getDisplayName() + " " + ARTIFACT_DISPLAY_NAME)); @@ -492,9 +500,9 @@ public class Tags implements AutopsyVisitableItem { private void updateDisplayName() { long tagsCount = 0; try { - tagsCount = UserPreferences.groupItemsInTreeByDatasource() ? - Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName, datasourceObjId) : - Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName); + tagsCount = UserPreferences.groupItemsInTreeByDatasource() + ? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName, datasourceObjId) + : Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName); } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(BlackboardArtifactTagTypeNode.class.getName()).log(Level.SEVERE, "Failed to get blackboard artifact tags count for " + tagName.getDisplayName() + " tag name", ex); //NON-NLS } @@ -549,10 +557,20 @@ public class Tags implements AutopsyVisitableItem { protected boolean createKeys(List keys) { try { // Use the blackboard artifact tags bearing the specified tag name as the keys. - List artifactTags = UserPreferences.groupItemsInTreeByDatasource() ? - Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName, datasourceObjId) : - Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName); - keys.addAll(artifactTags); + List artifactTags = UserPreferences.groupItemsInTreeByDatasource() + ? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName, datasourceObjId) + : Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName); + if (UserPreferences.showOnlyCurrentUserTags()) { + String userName = System.getProperty("user.name"); + for (BlackboardArtifactTag tag : artifactTags){ + if (userName.equals(tag.getUserName())){ + keys.add(tag); + } + } + } + else { + keys.addAll(artifactTags); + } } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(BlackboardArtifactTagNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties index 926c4b4626..24818139af 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties @@ -124,4 +124,5 @@ GroupDataSourcesDialog.dataSourceCountLabel.text=jLabel1 GroupDataSourcesDialog.queryLabel.text=Would you like to group by data source for faster loading? GroupDataSourcesDialog.yesButton.text=Yes GroupDataSourcesDialog.noButton.text=No -GroupDataSourcesDialog.title=Group by Data Source? \ No newline at end of file +GroupDataSourcesDialog.title=Group by Data Source? +DirectoryTreeTopComponent.showOnlyCurrentUserTagsCheckbox.text=X diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.form b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.form index 732e34c20b..6ca508789c 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.form +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.form @@ -21,7 +21,9 @@ - + + + @@ -36,7 +38,10 @@ - + + + + @@ -151,5 +156,15 @@ + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index fb9ded33e2..b20a71db5c 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -137,6 +137,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat forwardButton.setEnabled(false); groupByDatasourceCheckBox.setSelected(UserPreferences.groupItemsInTreeByDatasource()); + showOnlyCurrentUserTagsCheckbox.setSelected(UserPreferences.showOnlyCurrentUserTags()); } /** @@ -191,6 +192,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat forwardButton = new javax.swing.JButton(); showRejectedCheckBox = new javax.swing.JCheckBox(); groupByDatasourceCheckBox = new javax.swing.JCheckBox(); + showOnlyCurrentUserTagsCheckbox = new javax.swing.JCheckBox(); treeView.setBorder(null); @@ -235,6 +237,13 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat } }); + org.openide.awt.Mnemonics.setLocalizedText(showOnlyCurrentUserTagsCheckbox, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.showOnlyCurrentUserTagsCheckbox.text")); // NOI18N + showOnlyCurrentUserTagsCheckbox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + showOnlyCurrentUserTagsCheckboxActionPerformed(evt); + } + }); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -244,7 +253,9 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat .addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 51, Short.MAX_VALUE) + .addGap(18, 18, 18) + .addComponent(showOnlyCurrentUserTagsCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, 33, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(showRejectedCheckBox) .addComponent(groupByDatasourceCheckBox)) @@ -256,7 +267,9 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(5, 5, 5) - .addComponent(showRejectedCheckBox) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(showRejectedCheckBox) + .addComponent(showOnlyCurrentUserTagsCheckbox)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(groupByDatasourceCheckBox)) .addGroup(layout.createSequentialGroup() @@ -323,10 +336,15 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat UserPreferences.setGroupItemsInTreeByDatasource(this.groupByDatasourceCheckBox.isSelected()); }//GEN-LAST:event_groupByDatasourceCheckBoxActionPerformed + private void showOnlyCurrentUserTagsCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showOnlyCurrentUserTagsCheckboxActionPerformed + UserPreferences.setShowOnlyCurrentUserTags(this.showOnlyCurrentUserTagsCheckbox.isSelected()); + }//GEN-LAST:event_showOnlyCurrentUserTagsCheckboxActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton backButton; private javax.swing.JButton forwardButton; private javax.swing.JCheckBox groupByDatasourceCheckBox; + private javax.swing.JCheckBox showOnlyCurrentUserTagsCheckbox; private javax.swing.JCheckBox showRejectedCheckBox; private javax.swing.JScrollPane treeView; // End of variables declaration//GEN-END:variables From 75fed47b97b0d910fa96d051b193eea557acda93 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 24 Jul 2018 16:49:34 -0400 Subject: [PATCH 077/105] 4065 resolve conflict in DirectorTreeTopComponent with develop --- Core/src/org/sleuthkit/autopsy/core/UserPreferences.java | 2 +- Core/src/org/sleuthkit/autopsy/datamodel/Tags.java | 6 +++++- .../autopsy/directorytree/DirectoryTreeTopComponent.java | 8 ++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java index 9869001067..970ca9f0b0 100644 --- a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java +++ b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java @@ -70,7 +70,7 @@ public final class UserPreferences { private static final String MAX_NUM_OF_LOG_FILE = "MaximumNumberOfLogFiles"; private static final int LOG_FILE_NUM_INT = 10; public static final String GROUP_ITEMS_IN_TREE_BY_DATASOURCE = "GroupItemsInTreeByDataSource"; //NON-NLS - private static final String SHOW_ONLY_CURRENT_USER_TAGS = "ShowOnlyCurrentUserTags"; + public static final String SHOW_ONLY_CURRENT_USER_TAGS = "ShowOnlyCurrentUserTags"; // Prevent instantiation. private UserPreferences() { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index 643f3ecda6..b70e88957b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -103,7 +103,6 @@ public class Tags implements AutopsyVisitableItem { super.setName(DISPLAY_NAME); super.setDisplayName(DISPLAY_NAME); this.setIconBaseWithExtension(ICON_PATH); - } @Override @@ -133,6 +132,11 @@ public class Tags implements AutopsyVisitableItem { public String getItemType() { return getClass().getName(); } + + public void refresh(){ + tagResults.update(); + } + } private class TagNameNodeFactory extends ChildFactory.Detachable implements Observer { diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index b20a71db5c..83038c5421 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -81,6 +81,7 @@ import org.sleuthkit.autopsy.datamodel.InterestingHits; import org.sleuthkit.autopsy.datamodel.KeywordHits; import org.sleuthkit.autopsy.datamodel.ResultsNode; import org.sleuthkit.autopsy.datamodel.AutopsyTreeChildFactory; +import org.sleuthkit.autopsy.datamodel.Tags; import org.sleuthkit.autopsy.datamodel.ViewsNode; import org.sleuthkit.autopsy.datamodel.accounts.Accounts; import org.sleuthkit.autopsy.datamodel.accounts.BINRange; @@ -153,6 +154,9 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat case UserPreferences.GROUP_ITEMS_IN_TREE_BY_DATASOURCE: refreshContentTreeSafe(); break; + case UserPreferences.SHOW_ONLY_CURRENT_USER_TAGS: + refreshTagsTree(); + break; case UserPreferences.HIDE_KNOWN_FILES_IN_VIEWS_TREE: case UserPreferences.HIDE_SLACK_FILES_IN_VIEWS_TREE: // TODO: Need a way to refresh the Views subtree @@ -908,6 +912,10 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat SwingUtilities.invokeLater(this::rebuildTree); } + private void refreshTagsTree() { + ((Tags.RootNode)autopsyTreeChildren.findChild("Tags")).refresh(); + } + /** * Rebuilds the autopsy tree. * From b86307de6044b9704b97351ba0ccbce1b1bbd3bd Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 24 Jul 2018 18:24:27 -0400 Subject: [PATCH 078/105] 4065 continued conflict resolution while cherry-picking --- .../sleuthkit/autopsy/casemodule/Case.java | 9 ++++- .../events/TagTreeRefreshEvent.java | 27 +++++++++++++++ .../casemodule/services/TagsManager.java | 28 +++++++++++++-- .../org/sleuthkit/autopsy/datamodel/Tags.java | 34 ++++++++----------- .../DirectoryTreeTopComponent.java | 14 +++++++- 5 files changed, 89 insertions(+), 23 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/casemodule/events/TagTreeRefreshEvent.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 9019ae162d..92789c6998 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -75,6 +75,7 @@ import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.casemodule.events.DataSourceAddedEvent; import org.sleuthkit.autopsy.casemodule.events.ReportAddedEvent; +import org.sleuthkit.autopsy.casemodule.events.TagTreeRefreshEvent; import org.sleuthkit.autopsy.casemodule.services.Services; import org.sleuthkit.autopsy.commonfilesearch.CommonFilesSearchAction; import org.sleuthkit.autopsy.communications.OpenCommVisualizationToolAction; @@ -372,7 +373,9 @@ public class Case { * old value of the PropertyChangeEvent is the display name of the tag * definition that has changed. */ - TAG_DEFINITION_CHANGED; + TAG_DEFINITION_CHANGED, + + REFRESH_TAG_TREE; }; @@ -1510,6 +1513,10 @@ public class Case { eventPublisher.publish(new ContentTagAddedEvent(newTag)); } + public void notifyTagsTreeRefresh(){ + eventPublisher.publish(new TagTreeRefreshEvent()); + } + /** * Notifies case event subscribers that a content tag has been deleted. * diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/events/TagTreeRefreshEvent.java b/Core/src/org/sleuthkit/autopsy/casemodule/events/TagTreeRefreshEvent.java new file mode 100644 index 0000000000..ce3640d267 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/events/TagTreeRefreshEvent.java @@ -0,0 +1,27 @@ +/* + * 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.casemodule.events; + +import java.io.Serializable; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.events.AutopsyEvent; + +/** + * + * @author wschaefer + */ +public class TagTreeRefreshEvent extends AutopsyEvent implements Serializable{ + + private static final long serialVersionUID = 1L; + + public TagTreeRefreshEvent(){ + this(Case.Events.REFRESH_TAG_TREE.toString(), true, false); + } + private TagTreeRefreshEvent(String eventName, Object oldValue, Object newValue) { + super(eventName, oldValue, newValue); + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 786e461619..772dd8afe2 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -644,7 +644,19 @@ public class TagsManager implements Closeable { * the case database. */ public long getBlackboardArtifactTagsCountByTagName(TagName tagName) throws TskCoreException { - return caseDb.getBlackboardArtifactTagsCountByTagName(tagName); + if (UserPreferences.showOnlyCurrentUserTags()) { + String userName = System.getProperty("user.name"); + long count = 0; + List artifactTags = getBlackboardArtifactTagsByTagName(tagName); + for (BlackboardArtifactTag tag : artifactTags) { + if (userName.equals(tag.getUserName())) { + count++; + } + } + return count; + } else { + return caseDb.getBlackboardArtifactTagsCountByTagName(tagName); + } } /** @@ -662,7 +674,19 @@ public class TagsManager implements Closeable { * the case database. */ public long getBlackboardArtifactTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException { - return caseDb.getBlackboardArtifactTagsCountByTagName(tagName, dsObjId); + if (UserPreferences.showOnlyCurrentUserTags()) { + String userName = System.getProperty("user.name"); + long count = 0; + List artifactTags = getBlackboardArtifactTagsByTagName(tagName, dsObjId); + for (BlackboardArtifactTag tag : artifactTags) { + if (userName.equals(tag.getUserName())) { + count++; + } + } + return count; + } else { + return caseDb.getBlackboardArtifactTagsCountByTagName(tagName, dsObjId); + } } /** diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index b70e88957b..0bb3eedde3 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -132,11 +132,7 @@ public class Tags implements AutopsyVisitableItem { public String getItemType() { return getClass().getName(); } - - public void refresh(){ - tagResults.update(); - } - + } private class TagNameNodeFactory extends ChildFactory.Detachable implements Observer { @@ -147,7 +143,8 @@ public class Tags implements AutopsyVisitableItem { Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED, Case.Events.CONTENT_TAG_ADDED, Case.Events.CONTENT_TAG_DELETED, - Case.Events.CURRENT_CASE); + Case.Events.CURRENT_CASE, + Case.Events.REFRESH_TAG_TREE); private final PropertyChangeListener pcl = new PropertyChangeListener() { @Override @@ -156,7 +153,8 @@ public class Tags implements AutopsyVisitableItem { if (eventType.equals(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED.toString()) || eventType.equals(Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED.toString()) || eventType.equals(Case.Events.CONTENT_TAG_ADDED.toString()) - || eventType.equals(Case.Events.CONTENT_TAG_DELETED.toString())) { + || eventType.equals(Case.Events.CONTENT_TAG_DELETED.toString()) + || eventType.equals(Case.Events.REFRESH_TAG_TREE.toString())) { /** * Checking for a current case is a stop gap measure until a * different way of handling the closing of cases is worked @@ -451,14 +449,13 @@ public class Tags implements AutopsyVisitableItem { : Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName); if (UserPreferences.showOnlyCurrentUserTags()) { String userName = System.getProperty("user.name"); - for (ContentTag tag : contentTags){ - if (userName.equals(tag.getUserName())){ + for (ContentTag tag : contentTags) { + if (userName.equals(tag.getUserName())) { keys.add(tag); - } + } } - } - else { - keys.addAll(contentTags); + } else { + keys.addAll(contentTags); } } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(ContentTagNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS @@ -566,14 +563,13 @@ public class Tags implements AutopsyVisitableItem { : Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName); if (UserPreferences.showOnlyCurrentUserTags()) { String userName = System.getProperty("user.name"); - for (BlackboardArtifactTag tag : artifactTags){ - if (userName.equals(tag.getUserName())){ + for (BlackboardArtifactTag tag : artifactTags) { + if (userName.equals(tag.getUserName())) { keys.add(tag); - } + } } - } - else { - keys.addAll(artifactTags); + } else { + keys.addAll(artifactTags); } } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(BlackboardArtifactTagNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 83038c5421..4305278446 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -913,7 +913,19 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat } private void refreshTagsTree() { - ((Tags.RootNode)autopsyTreeChildren.findChild("Tags")).refresh(); + SwingUtilities.invokeLater(() -> { + // if no open case or has no data then there is no tree to rebuild + Case currentCase; + try { + currentCase = Case.getCurrentCaseThrows(); + } catch (NoCurrentCaseException ex) { + return; + } + if (null == currentCase || currentCase.hasData() == false) { + return; + } + currentCase.notifyTagsTreeRefresh(); + }); } /** From 5a50721b3331f4419ba7ae1ff5edd6b105ffd174 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 25 Jul 2018 12:57:35 -0400 Subject: [PATCH 079/105] 4065 continued conflict resolution while cherry-picking --- .../sleuthkit/autopsy/casemodule/Case.java | 4 +-- .../events/TagTreeRefreshEvent.java | 27 ------------------- .../org/sleuthkit/autopsy/datamodel/Tags.java | 10 ++++--- .../autopsy/directorytree/Bundle.properties | 2 +- .../DirectoryTreeTopComponent.form | 2 +- .../DirectoryTreeTopComponent.java | 15 +++-------- 6 files changed, 12 insertions(+), 48 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/casemodule/events/TagTreeRefreshEvent.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 92789c6998..f40fed2143 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -373,9 +373,7 @@ public class Case { * old value of the PropertyChangeEvent is the display name of the tag * definition that has changed. */ - TAG_DEFINITION_CHANGED, - - REFRESH_TAG_TREE; + TAG_DEFINITION_CHANGED; }; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/events/TagTreeRefreshEvent.java b/Core/src/org/sleuthkit/autopsy/casemodule/events/TagTreeRefreshEvent.java deleted file mode 100644 index ce3640d267..0000000000 --- a/Core/src/org/sleuthkit/autopsy/casemodule/events/TagTreeRefreshEvent.java +++ /dev/null @@ -1,27 +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.casemodule.events; - -import java.io.Serializable; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.events.AutopsyEvent; - -/** - * - * @author wschaefer - */ -public class TagTreeRefreshEvent extends AutopsyEvent implements Serializable{ - - private static final long serialVersionUID = 1L; - - public TagTreeRefreshEvent(){ - this(Case.Events.REFRESH_TAG_TREE.toString(), true, false); - } - private TagTreeRefreshEvent(String eventName, Object oldValue, Object newValue) { - super(eventName, oldValue, newValue); - } - -} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index 0bb3eedde3..cac9306a14 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -132,6 +132,10 @@ public class Tags implements AutopsyVisitableItem { public String getItemType() { return getClass().getName(); } + + public void refresh(){ + tagResults.update(); + } } @@ -143,8 +147,7 @@ public class Tags implements AutopsyVisitableItem { Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED, Case.Events.CONTENT_TAG_ADDED, Case.Events.CONTENT_TAG_DELETED, - Case.Events.CURRENT_CASE, - Case.Events.REFRESH_TAG_TREE); + Case.Events.CURRENT_CASE); private final PropertyChangeListener pcl = new PropertyChangeListener() { @Override @@ -153,8 +156,7 @@ public class Tags implements AutopsyVisitableItem { if (eventType.equals(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED.toString()) || eventType.equals(Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED.toString()) || eventType.equals(Case.Events.CONTENT_TAG_ADDED.toString()) - || eventType.equals(Case.Events.CONTENT_TAG_DELETED.toString()) - || eventType.equals(Case.Events.REFRESH_TAG_TREE.toString())) { + || eventType.equals(Case.Events.CONTENT_TAG_DELETED.toString())) { /** * Checking for a current case is a stop gap measure until a * different way of handling the closing of cases is worked diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties index 24818139af..b90711b8d9 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties @@ -125,4 +125,4 @@ GroupDataSourcesDialog.queryLabel.text=Would you like to group by data source fo GroupDataSourcesDialog.yesButton.text=Yes GroupDataSourcesDialog.noButton.text=No GroupDataSourcesDialog.title=Group by Data Source? -DirectoryTreeTopComponent.showOnlyCurrentUserTagsCheckbox.text=X +DirectoryTreeTopComponent.showOnlyCurrentUserTagsCheckbox.text=Hide Other User's Tags diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.form b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.form index 6ca508789c..8fa8265e06 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.form +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.form @@ -22,7 +22,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 4305278446..71fd0c5a2d 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -258,7 +258,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(18, 18, 18) - .addComponent(showOnlyCurrentUserTagsCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, 33, Short.MAX_VALUE) + .addComponent(showOnlyCurrentUserTagsCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(showRejectedCheckBox) @@ -914,17 +914,8 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat private void refreshTagsTree() { SwingUtilities.invokeLater(() -> { - // if no open case or has no data then there is no tree to rebuild - Case currentCase; - try { - currentCase = Case.getCurrentCaseThrows(); - } catch (NoCurrentCaseException ex) { - return; - } - if (null == currentCase || currentCase.hasData() == false) { - return; - } - currentCase.notifyTagsTreeRefresh(); + // if no open case or has no data then there is no tree to rebuild + ((Tags.RootNode) autopsyTreeChildren.findChild("Tags")).refresh(); }); } From 764c3e4a06b49056b1e1952654f22afcadae003d Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 25 Jul 2018 13:21:01 -0400 Subject: [PATCH 080/105] 4065 finish removal of tag refresh event --- Core/src/org/sleuthkit/autopsy/casemodule/Case.java | 7 +------ .../sleuthkit/autopsy/casemodule/services/TagsManager.java | 4 ++-- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index f40fed2143..0d2556c438 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -75,7 +75,6 @@ import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.casemodule.events.DataSourceAddedEvent; import org.sleuthkit.autopsy.casemodule.events.ReportAddedEvent; -import org.sleuthkit.autopsy.casemodule.events.TagTreeRefreshEvent; import org.sleuthkit.autopsy.casemodule.services.Services; import org.sleuthkit.autopsy.commonfilesearch.CommonFilesSearchAction; import org.sleuthkit.autopsy.communications.OpenCommVisualizationToolAction; @@ -1510,11 +1509,7 @@ public class Case { public void notifyContentTagAdded(ContentTag newTag) { eventPublisher.publish(new ContentTagAddedEvent(newTag)); } - - public void notifyTagsTreeRefresh(){ - eventPublisher.publish(new TagTreeRefreshEvent()); - } - + /** * Notifies case event subscribers that a content tag has been deleted. * diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 772dd8afe2..cae9aa0308 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -181,7 +181,7 @@ public class TagsManager implements Closeable { tagNameSet.add(tag.getName()); } } - return new ArrayList(tagNameSet); + return new ArrayList(tagNameSet); } else { return caseDb.getTagNamesInUse(); } @@ -216,7 +216,7 @@ public class TagsManager implements Closeable { tagNameSet.add(tag.getName()); } } - return new ArrayList(tagNameSet); + return new ArrayList(tagNameSet); } else { return caseDb.getTagNamesInUse(dsObjId); } From f772010fc2b3eea3d720c7762c8f318e3b57447d Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 25 Jul 2018 14:46:40 -0400 Subject: [PATCH 081/105] 4065 fix non event refresh for group by data source --- .../casemodule/services/TagsManager.java | 4 ++-- .../DirectoryTreeTopComponent.java | 17 +++++++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index cae9aa0308..aacad1ce7a 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -181,7 +181,7 @@ public class TagsManager implements Closeable { tagNameSet.add(tag.getName()); } } - return new ArrayList(tagNameSet); + return new ArrayList<>(tagNameSet); } else { return caseDb.getTagNamesInUse(); } @@ -216,7 +216,7 @@ public class TagsManager implements Closeable { tagNameSet.add(tag.getName()); } } - return new ArrayList(tagNameSet); + return new ArrayList<>(tagNameSet); } else { return caseDb.getTagNamesInUse(dsObjId); } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 71fd0c5a2d..51133e76b3 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -914,8 +914,21 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat private void refreshTagsTree() { SwingUtilities.invokeLater(() -> { - // if no open case or has no data then there is no tree to rebuild - ((Tags.RootNode) autopsyTreeChildren.findChild("Tags")).refresh(); + // if no open case or has no data then there is no tree to rebuild + if (UserPreferences.groupItemsInTreeByDatasource()) { + for (Node dataSource : autopsyTreeChildren.getNodes()) { + Node tagsNode = dataSource.getChildren().findChild("Tags"); + if (tagsNode != null) { + //Reports is at the same level as the data sources so we want to ignore it + ((Tags.RootNode)tagsNode).refresh(); + } + } + } else { + Node tagsNode = autopsyTreeChildren.findChild("Tags"); + if (tagsNode != null) { + ((Tags.RootNode)tagsNode).refresh(); + } + } }); } From efbd58fd34bb273351ebe9fbaa44dfeb6f366781 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 25 Jul 2018 15:05:36 -0400 Subject: [PATCH 082/105] 4065 replace static text with text from bundle message --- Core/src/org/sleuthkit/autopsy/datamodel/Tags.java | 6 +++++- .../autopsy/directorytree/DirectoryTreeTopComponent.java | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index cac9306a14..97af746282 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -55,7 +55,7 @@ public class Tags implements AutopsyVisitableItem { // override of Children.Keys.createNodes(). private final TagResults tagResults = new TagResults(); - private final String DISPLAY_NAME = NbBundle.getMessage(RootNode.class, "TagsNode.displayName.text"); + private final static String DISPLAY_NAME = NbBundle.getMessage(RootNode.class, "TagsNode.displayName.text"); private final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS private final long datasourceObjId; @@ -68,6 +68,10 @@ public class Tags implements AutopsyVisitableItem { this.datasourceObjId = dsObjId; } + public static String getTagsDisplayName(){ + return DISPLAY_NAME; + } + long filteringDataSourceObjId() { return this.datasourceObjId; } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 51133e76b3..469a3c62dd 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -917,14 +917,14 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat // if no open case or has no data then there is no tree to rebuild if (UserPreferences.groupItemsInTreeByDatasource()) { for (Node dataSource : autopsyTreeChildren.getNodes()) { - Node tagsNode = dataSource.getChildren().findChild("Tags"); + Node tagsNode = dataSource.getChildren().findChild(Tags.getTagsDisplayName()); if (tagsNode != null) { //Reports is at the same level as the data sources so we want to ignore it ((Tags.RootNode)tagsNode).refresh(); } } } else { - Node tagsNode = autopsyTreeChildren.findChild("Tags"); + Node tagsNode = autopsyTreeChildren.findChild(Tags.getTagsDisplayName()); if (tagsNode != null) { ((Tags.RootNode)tagsNode).refresh(); } From 6baf076f98212aaba22f1da01ba467e7a22f7709 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 26 Jul 2018 17:27:41 -0400 Subject: [PATCH 083/105] 4065 clean up and comments for hiding tags other than the current users --- .../org/sleuthkit/autopsy/casemodule/Case.java | 2 +- .../casemodule/services/TagsManager.java | 16 +++++++--------- .../autopsy/core/UserPreferences.java | 13 +++++++++++++ .../org/sleuthkit/autopsy/datamodel/Tags.java | 18 +++++++++++++----- .../DirectoryTreeTopComponent.java | 3 +++ 5 files changed, 37 insertions(+), 15 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 0d2556c438..9019ae162d 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -1509,7 +1509,7 @@ public class Case { public void notifyContentTagAdded(ContentTag newTag) { eventPublisher.publish(new ContentTagAddedEvent(newTag)); } - + /** * Notifies case event subscribers that a content tag has been deleted. * diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index aacad1ce7a..d2b0b041cf 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -48,7 +48,7 @@ import org.sleuthkit.datamodel.TskData; public class TagsManager implements Closeable { private static final Logger LOGGER = Logger.getLogger(TagsManager.class.getName()); - + private static final String USER_NAME_PROPERTY = "user.name"; private final SleuthkitCase caseDb; /** @@ -166,9 +166,8 @@ public class TagsManager implements Closeable { */ public List getTagNamesInUse() throws TskCoreException { if (UserPreferences.showOnlyCurrentUserTags()) { -// return caseDb.getTagNamesInUse(System.getProperty("user.name")); Set tagNameSet = new HashSet<>(); - String userName = System.getProperty("user.name"); + String userName = System.getProperty(USER_NAME_PROPERTY); List artifactTags = caseDb.getAllBlackboardArtifactTags(); for (BlackboardArtifactTag tag : artifactTags) { if (tag.getUserName().equals(userName)) { @@ -201,9 +200,8 @@ public class TagsManager implements Closeable { */ public List getTagNamesInUse(long dsObjId) throws TskCoreException { if (UserPreferences.showOnlyCurrentUserTags()) { -// return caseDb.getTagNamesInUse(dsObjId, System.getProperty("user.name")); Set tagNameSet = new HashSet<>(); - String userName = System.getProperty("user.name"); + String userName = System.getProperty(USER_NAME_PROPERTY); List artifactTags = caseDb.getAllBlackboardArtifactTags(); for (BlackboardArtifactTag tag : artifactTags) { if (tag.getUserName().equals(userName) && tag.getArtifact().getDataSource().getId() == dsObjId) { @@ -455,7 +453,7 @@ public class TagsManager implements Closeable { */ public long getContentTagsCountByTagName(TagName tagName) throws TskCoreException { if (UserPreferences.showOnlyCurrentUserTags()) { - String userName = System.getProperty("user.name"); + String userName = System.getProperty(USER_NAME_PROPERTY); long count = 0; List contentTags = getContentTagsByTagName(tagName); for (ContentTag tag : contentTags) { @@ -486,7 +484,7 @@ public class TagsManager implements Closeable { */ public long getContentTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException { if (UserPreferences.showOnlyCurrentUserTags()) { - String userName = System.getProperty("user.name"); + String userName = System.getProperty(USER_NAME_PROPERTY); long count = 0; List contentTags = getContentTagsByTagName(tagName, dsObjId); for (ContentTag tag : contentTags) { @@ -645,7 +643,7 @@ public class TagsManager implements Closeable { */ public long getBlackboardArtifactTagsCountByTagName(TagName tagName) throws TskCoreException { if (UserPreferences.showOnlyCurrentUserTags()) { - String userName = System.getProperty("user.name"); + String userName = System.getProperty(USER_NAME_PROPERTY); long count = 0; List artifactTags = getBlackboardArtifactTagsByTagName(tagName); for (BlackboardArtifactTag tag : artifactTags) { @@ -675,7 +673,7 @@ public class TagsManager implements Closeable { */ public long getBlackboardArtifactTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException { if (UserPreferences.showOnlyCurrentUserTags()) { - String userName = System.getProperty("user.name"); + String userName = System.getProperty(USER_NAME_PROPERTY); long count = 0; List artifactTags = getBlackboardArtifactTagsByTagName(tagName, dsObjId); for (BlackboardArtifactTag tag : artifactTags) { diff --git a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java index 970ca9f0b0..78b726111e 100644 --- a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java +++ b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java @@ -197,10 +197,23 @@ public final class UserPreferences { preferences.putBoolean(GROUP_ITEMS_IN_TREE_BY_DATASOURCE, value); } + /** + * Get the user preference which identifies whether tags should be shown for + * only the current user or all users. + * + * @return true for just the current user, false for all users + */ public static boolean showOnlyCurrentUserTags() { return preferences.getBoolean(SHOW_ONLY_CURRENT_USER_TAGS, false); } + + /** + * Set the user preference which identifies whether tags should be shown for + * only the current user or all users. + * + * @param value - true for just the current user, false for all users + */ public static void setShowOnlyCurrentUserTags(boolean value) { preferences.putBoolean(SHOW_ONLY_CURRENT_USER_TAGS, value); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index 97af746282..d11bcf49a3 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -68,10 +68,15 @@ public class Tags implements AutopsyVisitableItem { this.datasourceObjId = dsObjId; } - public static String getTagsDisplayName(){ + /** + * Return the display name used by the tags node in the tree. + * + * @return - DISPLAY_NAME + */ + public static String getTagsDisplayName() { return DISPLAY_NAME; } - + long filteringDataSourceObjId() { return this.datasourceObjId; } @@ -136,9 +141,12 @@ public class Tags implements AutopsyVisitableItem { public String getItemType() { return getClass().getName(); } - - public void refresh(){ - tagResults.update(); + + /** + * Cause the contents of the RootNode and its children to be updated. + */ + public void refresh() { + tagResults.update(); } } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 469a3c62dd..17cac06732 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -912,6 +912,9 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat SwingUtilities.invokeLater(this::rebuildTree); } + /** + * Refresh only the tags subtree(s) of the tree view. + */ private void refreshTagsTree() { SwingUtilities.invokeLater(() -> { // if no open case or has no data then there is no tree to rebuild From 215f76ad9990d1b5985776e1952b8ec90347bd6a Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 27 Jul 2018 11:12:06 -0400 Subject: [PATCH 084/105] 4065 move use of userName filter setting to Tags tree out of Tags Manager --- .../casemodule/services/TagsManager.java | 234 ++++++++++++------ .../org/sleuthkit/autopsy/datamodel/Tags.java | 70 ++++-- 2 files changed, 206 insertions(+), 98 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index d2b0b041cf..058f7accdf 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -48,7 +48,6 @@ import org.sleuthkit.datamodel.TskData; public class TagsManager implements Closeable { private static final Logger LOGGER = Logger.getLogger(TagsManager.class.getName()); - private static final String USER_NAME_PROPERTY = "user.name"; private final SleuthkitCase caseDb; /** @@ -165,25 +164,34 @@ public class TagsManager implements Closeable { * @throws TskCoreException If there is an error querying the case database. */ public List getTagNamesInUse() throws TskCoreException { - if (UserPreferences.showOnlyCurrentUserTags()) { - Set tagNameSet = new HashSet<>(); - String userName = System.getProperty(USER_NAME_PROPERTY); - List artifactTags = caseDb.getAllBlackboardArtifactTags(); - for (BlackboardArtifactTag tag : artifactTags) { - if (tag.getUserName().equals(userName)) { - tagNameSet.add(tag.getName()); - } + return caseDb.getTagNamesInUse(); + } + + /** + * Gets a list of all tag names currently in use in the case database for + * tagging content or artifacts by the specified user. + * + * @param userName - the user name that you want to get tags for + * + * @return A list, possibly empty, of TagName objects. + * + * @throws TskCoreException If there is an error querying the case database. + */ + public List getTagNamesInUseForUser(String userName) throws TskCoreException { + Set tagNameSet = new HashSet<>(); + List artifactTags = caseDb.getAllBlackboardArtifactTags(); + for (BlackboardArtifactTag tag : artifactTags) { + if (tag.getUserName().equals(userName)) { + tagNameSet.add(tag.getName()); } - List contentTags = caseDb.getAllContentTags(); - for (ContentTag tag : contentTags) { - if (tag.getUserName().equals(userName)) { - tagNameSet.add(tag.getName()); - } - } - return new ArrayList<>(tagNameSet); - } else { - return caseDb.getTagNamesInUse(); } + List contentTags = caseDb.getAllContentTags(); + for (ContentTag tag : contentTags) { + if (tag.getUserName().equals(userName)) { + tagNameSet.add(tag.getName()); + } + } + return new ArrayList<>(tagNameSet); } /** @@ -199,25 +207,37 @@ public class TagsManager implements Closeable { * @throws TskCoreException */ public List getTagNamesInUse(long dsObjId) throws TskCoreException { - if (UserPreferences.showOnlyCurrentUserTags()) { - Set tagNameSet = new HashSet<>(); - String userName = System.getProperty(USER_NAME_PROPERTY); - List artifactTags = caseDb.getAllBlackboardArtifactTags(); - for (BlackboardArtifactTag tag : artifactTags) { - if (tag.getUserName().equals(userName) && tag.getArtifact().getDataSource().getId() == dsObjId) { - tagNameSet.add(tag.getName()); - } + return caseDb.getTagNamesInUse(dsObjId); + } + + /** + * Selects all of the rows from the tag_names table in the case database for + * which there is at least one matching row in the content_tags or + * blackboard_artifact_tags tables, for the given data source object id and user. + * + * @param dsObjId data source object id + * @param userName - the user name that you want to get tags for + * + * @return A list, possibly empty, of TagName data transfer objects (DTOs) + * for the rows. + * + * @throws TskCoreException + */ + public List getTagNamesInUseForUser(long dsObjId, String userName) throws TskCoreException { + Set tagNameSet = new HashSet<>(); + List artifactTags = caseDb.getAllBlackboardArtifactTags(); + for (BlackboardArtifactTag tag : artifactTags) { + if (tag.getUserName().equals(userName) && tag.getArtifact().getDataSource().getId() == dsObjId) { + tagNameSet.add(tag.getName()); } - List contentTags = caseDb.getAllContentTags(); - for (ContentTag tag : contentTags) { - if (tag.getUserName().equals(userName) && tag.getContent().getDataSource().getId() == dsObjId) { - tagNameSet.add(tag.getName()); - } - } - return new ArrayList<>(tagNameSet); - } else { - return caseDb.getTagNamesInUse(dsObjId); } + List contentTags = caseDb.getAllContentTags(); + for (ContentTag tag : contentTags) { + if (tag.getUserName().equals(userName) && tag.getContent().getDataSource().getId() == dsObjId) { + tagNameSet.add(tag.getName()); + } + } + return new ArrayList<>(tagNameSet); } /** @@ -452,19 +472,32 @@ public class TagsManager implements Closeable { * the case database. */ public long getContentTagsCountByTagName(TagName tagName) throws TskCoreException { - if (UserPreferences.showOnlyCurrentUserTags()) { - String userName = System.getProperty(USER_NAME_PROPERTY); - long count = 0; - List contentTags = getContentTagsByTagName(tagName); - for (ContentTag tag : contentTags) { - if (userName.equals(tag.getUserName())) { - count++; - } + return caseDb.getContentTagsCountByTagName(tagName); + } + + /** + * Gets content tags count by tag name for the specified user. + * + * @param tagName The representation of the desired tag type in the case + * database, which can be obtained by calling getTagNames + * and/or addTagName. + * @param userName - the user name that you want to get tags for + * + * @return A count of the content tags with the specified tag name for the + * specified user. + * + * @throws TskCoreException If there is an error getting the tags count from + * the case database. + */ + public long getContentTagsCountByTagNameForUser(TagName tagName, String userName) throws TskCoreException { + long count = 0; + List contentTags = getContentTagsByTagName(tagName); + for (ContentTag tag : contentTags) { + if (userName.equals(tag.getUserName())) { + count++; } - return count; - } else { - return caseDb.getContentTagsCountByTagName(tagName); } + return count; } /** @@ -483,19 +516,34 @@ public class TagsManager implements Closeable { * the case database. */ public long getContentTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException { - if (UserPreferences.showOnlyCurrentUserTags()) { - String userName = System.getProperty(USER_NAME_PROPERTY); - long count = 0; - List contentTags = getContentTagsByTagName(tagName, dsObjId); - for (ContentTag tag : contentTags) { - if (userName.equals(tag.getUserName())) { - count++; - } + return caseDb.getContentTagsCountByTagName(tagName, dsObjId); + } + + /** + * Gets content tags count by tag name, for the given data source and user + * + * @param tagName The representation of the desired tag type in the case + * database, which can be obtained by calling getTagNames + * and/or addTagName. + * + * @param dsObjId data source object id + * @param userName - the user name that you want to get tags for + * + * @return A count of the content tags with the specified tag name, and for + * the given data source and user + * + * @throws TskCoreException If there is an error getting the tags count from + * the case database. + */ + public long getContentTagsCountByTagNameForUser(TagName tagName, long dsObjId, String userName) throws TskCoreException { + long count = 0; + List contentTags = getContentTagsByTagName(tagName, dsObjId); + for (ContentTag tag : contentTags) { + if (userName.equals(tag.getUserName())) { + count++; } - return count; - } else { - return caseDb.getContentTagsCountByTagName(tagName, dsObjId); } + return count; } /** @@ -642,19 +690,32 @@ public class TagsManager implements Closeable { * the case database. */ public long getBlackboardArtifactTagsCountByTagName(TagName tagName) throws TskCoreException { - if (UserPreferences.showOnlyCurrentUserTags()) { - String userName = System.getProperty(USER_NAME_PROPERTY); - long count = 0; - List artifactTags = getBlackboardArtifactTagsByTagName(tagName); - for (BlackboardArtifactTag tag : artifactTags) { - if (userName.equals(tag.getUserName())) { - count++; - } + return caseDb.getBlackboardArtifactTagsCountByTagName(tagName); + } + + /** + * Gets an artifact tags count by tag name for a specific user. + * + * @param tagName The representation of the desired tag type in the case + * database, which can be obtained by calling getTagNames + * and/or addTagName. + * @param userName - the user name that you want to get tags for + * + * @return A count of the artifact tags with the specified tag name for the + * specified user. + * + * @throws TskCoreException If there is an error getting the tags count from + * the case database. + */ + public long getBlackboardArtifactTagsCountByTagNameForUser(TagName tagName, String userName) throws TskCoreException { + long count = 0; + List artifactTags = getBlackboardArtifactTagsByTagName(tagName); + for (BlackboardArtifactTag tag : artifactTags) { + if (userName.equals(tag.getUserName())) { + count++; } - return count; - } else { - return caseDb.getBlackboardArtifactTagsCountByTagName(tagName); } + return count; } /** @@ -672,19 +733,34 @@ public class TagsManager implements Closeable { * the case database. */ public long getBlackboardArtifactTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException { - if (UserPreferences.showOnlyCurrentUserTags()) { - String userName = System.getProperty(USER_NAME_PROPERTY); - long count = 0; - List artifactTags = getBlackboardArtifactTagsByTagName(tagName, dsObjId); - for (BlackboardArtifactTag tag : artifactTags) { - if (userName.equals(tag.getUserName())) { - count++; - } + return caseDb.getBlackboardArtifactTagsCountByTagName(tagName, dsObjId); + } + + /** + * Gets an artifact tags count by tag name, for the given data source and + * user. + * + * @param tagName The representation of the desired tag type in the case + * database, which can be obtained by calling getTagNames + * and/or addTagName. + * @param dsObjId data source object id + * @param userName - the user name that you want to get tags for + * + * @return A count of the artifact tags with the specified tag name, for the + * given data source and user. + * + * @throws TskCoreException If there is an error getting the tags count from + * the case database. + */ + public long getBlackboardArtifactTagsCountByTagNameForUser(TagName tagName, long dsObjId, String userName) throws TskCoreException { + long count = 0; + List artifactTags = getBlackboardArtifactTagsByTagName(tagName, dsObjId); + for (BlackboardArtifactTag tag : artifactTags) { + if (userName.equals(tag.getUserName())) { + count++; } - return count; - } else { - return caseDb.getBlackboardArtifactTagsCountByTagName(tagName, dsObjId); } + return count; } /** diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index d11bcf49a3..b5f8ecff39 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -56,6 +56,7 @@ public class Tags implements AutopsyVisitableItem { private final TagResults tagResults = new TagResults(); private final static String DISPLAY_NAME = NbBundle.getMessage(RootNode.class, "TagsNode.displayName.text"); + private static final String USER_NAME_PROPERTY = "user.name"; //NON-NLS private final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS private final long datasourceObjId; @@ -240,10 +241,17 @@ public class Tags implements AutopsyVisitableItem { @Override protected boolean createKeys(List keys) { try { - - List tagNamesInUse = UserPreferences.groupItemsInTreeByDatasource() - ? Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse(datasourceObjId) - : Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse(); + List tagNamesInUse; + if (UserPreferences.showOnlyCurrentUserTags()) { + String userName = System.getProperty(USER_NAME_PROPERTY); + tagNamesInUse = UserPreferences.groupItemsInTreeByDatasource() + ? Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUseForUser(datasourceObjId, userName) + : Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUseForUser(userName); + } else { + tagNamesInUse = UserPreferences.groupItemsInTreeByDatasource() + ? Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse(datasourceObjId) + : Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse(); + } Collections.sort(tagNamesInUse); keys.addAll(tagNamesInUse); } catch (TskCoreException | NoCurrentCaseException ex) { @@ -291,14 +299,24 @@ public class Tags implements AutopsyVisitableItem { long tagsCount = 0; try { TagsManager tm = Case.getCurrentCaseThrows().getServices().getTagsManager(); - if (UserPreferences.groupItemsInTreeByDatasource()) { - tagsCount = tm.getContentTagsCountByTagName(tagName, datasourceObjId); - tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName, datasourceObjId); + if (UserPreferences.showOnlyCurrentUserTags()) { + String userName = System.getProperty(USER_NAME_PROPERTY); + if (UserPreferences.groupItemsInTreeByDatasource()) { + tagsCount = tm.getContentTagsCountByTagNameForUser(tagName, datasourceObjId, userName); + tagsCount += tm.getBlackboardArtifactTagsCountByTagNameForUser(tagName, datasourceObjId, userName); + } else { + tagsCount = tm.getContentTagsCountByTagNameForUser(tagName, userName); + tagsCount += tm.getBlackboardArtifactTagsCountByTagNameForUser(tagName, userName); + } } else { - tagsCount = tm.getContentTagsCountByTagName(tagName); - tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName); + if (UserPreferences.groupItemsInTreeByDatasource()) { + tagsCount = tm.getContentTagsCountByTagName(tagName, datasourceObjId); + tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName, datasourceObjId); + } else { + tagsCount = tm.getContentTagsCountByTagName(tagName); + tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName); + } } - } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(TagNameNode.class.getName()).log(Level.SEVERE, "Failed to get tags count for " + tagName.getDisplayName() + " tag name", ex); //NON-NLS } @@ -401,9 +419,17 @@ public class Tags implements AutopsyVisitableItem { private void updateDisplayName() { long tagsCount = 0; try { - tagsCount = UserPreferences.groupItemsInTreeByDatasource() - ? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName, datasourceObjId) - : Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName); + + if (UserPreferences.showOnlyCurrentUserTags()) { + String userName = System.getProperty(USER_NAME_PROPERTY); + tagsCount = UserPreferences.groupItemsInTreeByDatasource() + ? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagNameForUser(tagName, datasourceObjId, userName) + : Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagNameForUser(tagName, userName); + } else { + tagsCount = UserPreferences.groupItemsInTreeByDatasource() + ? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName, datasourceObjId) + : Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName); + } } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(ContentTagTypeNode.class.getName()).log(Level.SEVERE, "Failed to get content tags count for " + tagName.getDisplayName() + " tag name", ex); //NON-NLS } @@ -462,7 +488,7 @@ public class Tags implements AutopsyVisitableItem { ? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName, datasourceObjId) : Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName); if (UserPreferences.showOnlyCurrentUserTags()) { - String userName = System.getProperty("user.name"); + String userName = System.getProperty(USER_NAME_PROPERTY); for (ContentTag tag : contentTags) { if (userName.equals(tag.getUserName())) { keys.add(tag); @@ -501,7 +527,6 @@ public class Tags implements AutopsyVisitableItem { private final TagName tagName; private final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS - private int displayCount = 0; public BlackboardArtifactTagTypeNode(TagName tagName) { super(Children.create(new BlackboardArtifactTagNodeFactory(tagName), true), Lookups.singleton(tagName.getDisplayName() + " " + ARTIFACT_DISPLAY_NAME)); @@ -515,9 +540,16 @@ public class Tags implements AutopsyVisitableItem { private void updateDisplayName() { long tagsCount = 0; try { - tagsCount = UserPreferences.groupItemsInTreeByDatasource() - ? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName, datasourceObjId) - : Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName); + if (UserPreferences.showOnlyCurrentUserTags()) { + String userName = System.getProperty(USER_NAME_PROPERTY); + tagsCount = UserPreferences.groupItemsInTreeByDatasource() + ? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagNameForUser(tagName, datasourceObjId, userName) + : Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagNameForUser(tagName, userName); + } else { + tagsCount = UserPreferences.groupItemsInTreeByDatasource() + ? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName, datasourceObjId) + : Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName); + } } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(BlackboardArtifactTagTypeNode.class.getName()).log(Level.SEVERE, "Failed to get blackboard artifact tags count for " + tagName.getDisplayName() + " tag name", ex); //NON-NLS } @@ -576,7 +608,7 @@ public class Tags implements AutopsyVisitableItem { ? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName, datasourceObjId) : Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName); if (UserPreferences.showOnlyCurrentUserTags()) { - String userName = System.getProperty("user.name"); + String userName = System.getProperty(USER_NAME_PROPERTY); for (BlackboardArtifactTag tag : artifactTags) { if (userName.equals(tag.getUserName())) { keys.add(tag); From 2367bd5766cf78ce9ca2afe8fdf53ebbc28b5c4b Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 2 Aug 2018 16:31:46 -0400 Subject: [PATCH 085/105] 4065 fix codacy issue and formating issue found in review --- .../org/sleuthkit/autopsy/casemodule/services/TagsManager.java | 1 - Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 058f7accdf..896298c2bd 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -30,7 +30,6 @@ import java.util.logging.Level; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifactTag; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java index e213e460cb..acbfcac758 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java @@ -128,8 +128,7 @@ class ContentTagNode extends DisplayableItemNode { List actions = new ArrayList<>(); actions.addAll(Arrays.asList(super.getActions(context))); - AbstractFile file = getLookup().lookup(AbstractFile.class - ); + AbstractFile file = getLookup().lookup(AbstractFile.class); if (file != null) { actions.add(ViewFileInTimelineAction.createViewFileAction(file)); } From f583d309904a9bddcf90e680ee81bf8f40d738f9 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Fri, 3 Aug 2018 10:27:14 -0400 Subject: [PATCH 086/105] Added some of the codacy suggestions --- .../SevenZipExtractor.java | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java index 234275c41d..8b4abf3787 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java @@ -475,8 +475,6 @@ class SevenZipExtractor { List unpackedFiles = Collections.emptyList(); ISevenZipInArchive inArchive = null; - Map archiveDetailsMap = new LinkedHashMap<>(); - SevenZipContentReadStream stream = null; final ProgressHandle progress = ProgressHandle.createHandle(Bundle.EmbeddedFileExtractorIngestModule_ArchiveExtractor_moduleName()); //recursion depth check for zip bomb @@ -562,6 +560,7 @@ class SevenZipExtractor { freeDiskSpace = IngestMonitor.DISK_FREE_SPACE_UNKNOWN; } + Map archiveDetailsMap = new LinkedHashMap<>(); for (int inArchiveItemIndex = 0; inArchiveItemIndex < numItems; inArchiveItemIndex++) { String pathInArchive = getPathInArchive(inArchive, inArchiveItemIndex, archiveFile); String archiveItemPath = (String) inArchive.getProperty( @@ -662,7 +661,7 @@ class SevenZipExtractor { //inArchiveItemIndex. inArchive.extract(extractionIndices, false, archiveCallBack); - unpackSuccessful = unpackSuccessful & archiveCallBack.getSuccessFlag(); + unpackSuccessful = unpackSuccessful & archiveCallBack.wasSuccessful(); // add them to the DB. We wait until the end so that we have the metadata on all of the // intermediate nodes since the order is not guaranteed @@ -917,9 +916,9 @@ class SevenZipExtractor { */ private static class InArchiveItemDetails { - private SevenZipExtractor.UnpackedTree.UnpackedNode unpackedNode; - private String localAbsPath; - private String localRelPath; + private final SevenZipExtractor.UnpackedTree.UnpackedNode unpackedNode; + private final String localAbsPath; + private final String localRelPath; public InArchiveItemDetails( SevenZipExtractor.UnpackedTree.UnpackedNode unpackedNode, @@ -949,21 +948,21 @@ class SevenZipExtractor { private static class StandardIArchiveExtractCallback implements IArchiveExtractCallback, ICryptoGetTextPassword { - private AbstractFile archiveFile; - private ISevenZipInArchive inArchive; + private final AbstractFile archiveFile; + private final ISevenZipInArchive inArchive; private SevenZipExtractor.UnpackStream unpackStream = null; - private Map archiveDetailsMap; - private ProgressHandle progressHandle; + private final Map archiveDetailsMap; + private final ProgressHandle progressHandle; private int inArchiveItemIndex; - private long freeDiskSpace; + private final long freeDiskSpace; private long createTimeInSeconds; private long modTimeInSeconds; private long accessTimeInSeconds; private boolean isFolder; - private String password; + private final String password; private boolean unpackSuccessful = true; @@ -1070,11 +1069,11 @@ class SevenZipExtractor { } @Override - public void setTotal(long l) throws SevenZipException { + public void setTotal(long value) throws SevenZipException { } @Override - public void setCompleted(long l) throws SevenZipException { + public void setCompleted(long value) throws SevenZipException { } /** @@ -1089,7 +1088,7 @@ class SevenZipExtractor { return password; } - public boolean getSuccessFlag() { + public boolean wasSuccessful() { return unpackSuccessful; } } From 76adcc56a10aab8b41925b1b54db082c1454b282 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Fri, 3 Aug 2018 10:56:37 -0400 Subject: [PATCH 087/105] Cleaned up the final Codacy suggestions --- .../SevenZipExtractor.java | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java index 8b4abf3787..b1a0784648 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java @@ -562,17 +562,12 @@ class SevenZipExtractor { Map archiveDetailsMap = new LinkedHashMap<>(); for (int inArchiveItemIndex = 0; inArchiveItemIndex < numItems; inArchiveItemIndex++) { - String pathInArchive = getPathInArchive(inArchive, inArchiveItemIndex, archiveFile); - String archiveItemPath = (String) inArchive.getProperty( - inArchiveItemIndex, PropID.PATH); - Long archiveItemSize = (Long) inArchive.getProperty( - inArchiveItemIndex, PropID.SIZE); - if (isZipBombArchiveItemCheck(archiveFile, inArchive, inArchiveItemIndex, depthMap, escapedArchiveFilePath)) { unpackSuccessful = false; return unpackSuccessful; } + String pathInArchive = getPathInArchive(inArchive, inArchiveItemIndex, archiveFile); SevenZipExtractor.UnpackedTree.UnpackedNode unpackedNode = unpackedTree.addNode(pathInArchive); final boolean isEncrypted = (Boolean) inArchive.getProperty(inArchiveItemIndex, PropID.ENCRYPTED); @@ -586,11 +581,15 @@ class SevenZipExtractor { fullEncryption = false; } - // NOTE: item.getSize() may return null in case of certain + // NOTE: item size may return null in case of certain // archiving formats. Eg: BZ2 //check if unpacking this file will result in out of disk space //this is additional to zip bomb prevention mechanism + Long archiveItemSize = (Long) inArchive.getProperty( + inArchiveItemIndex, PropID.SIZE); if (freeDiskSpace != IngestMonitor.DISK_FREE_SPACE_UNKNOWN && archiveItemSize != null && archiveItemSize > 0) { //if free space is known and file is not empty. + String archiveItemPath = (String) inArchive.getProperty( + inArchiveItemIndex, PropID.PATH); long newDiskSpace = freeDiskSpace - archiveItemSize; if (newDiskSpace < MIN_FREE_DISK_SPACE) { String msg = NbBundle.getMessage(SevenZipExtractor.class, @@ -1026,8 +1025,8 @@ class SevenZipExtractor { /** * Pull necessary details from map to appropriately update unpackedNode - * info and provide useful logging messages. - * + * info and provide useful logging messages. This function is called + * after the internal framework has processed the stream. * * @param EOR - ExtractOperationResult * @@ -1035,17 +1034,14 @@ class SevenZipExtractor { */ @Override public void setOperationResult(ExtractOperationResult result) throws SevenZipException { - final SevenZipExtractor.UnpackedTree.UnpackedNode unpackedNode - = archiveDetailsMap.get(inArchiveItemIndex).getUnpackedNode(); - final String localRelPath = archiveDetailsMap.get( - inArchiveItemIndex).getLocalRelPath(); - final String localAbsPath = archiveDetailsMap.get( - inArchiveItemIndex).getLocalAbsPath(); - progressHandle.progress(archiveFile.getName() + ": " + (String) inArchive.getProperty(inArchiveItemIndex, PropID.PATH), inArchiveItemIndex); + final SevenZipExtractor.UnpackedTree.UnpackedNode unpackedNode + = archiveDetailsMap.get(inArchiveItemIndex).getUnpackedNode(); + final String localRelPath = archiveDetailsMap.get( + inArchiveItemIndex).getLocalRelPath(); if (isFolder) { unpackedNode.addDerivedInfo(0, !(Boolean) inArchive.getProperty(inArchiveItemIndex, PropID.IS_FOLDER), @@ -1053,7 +1049,9 @@ class SevenZipExtractor { localRelPath); return; } - + + final String localAbsPath = archiveDetailsMap.get( + inArchiveItemIndex).getLocalAbsPath(); if (result != ExtractOperationResult.OK) { logger.log(Level.WARNING, "Extraction of : {0} encountered error {1}", //NON-NLS new Object[]{localAbsPath, result}); @@ -1070,10 +1068,12 @@ class SevenZipExtractor { @Override public void setTotal(long value) throws SevenZipException { + //Not necessary for extract, left intenionally blank } @Override public void setCompleted(long value) throws SevenZipException { + //Not necessary for extract, left intenionally blank } /** From 4804c2f3cda323c75b6dcfb4ccd11735d1bd6993 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 3 Aug 2018 11:09:43 -0400 Subject: [PATCH 088/105] Changed Japanese button label to 'OK'. --- .../sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties index 431529542f..de05eaa8be 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties @@ -206,4 +206,4 @@ HashLookupSettingsPanel.nameLabel.text=\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c HashLookupSettingsPanel.hashDatabasesLabel.text=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\uff1a HashLookupSettingsPanel.importDatabaseButton.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u30a4\u30f3\u30dd\u30fc\u30c8 HashDbCreateDatabaseDialog.databasePathLabel.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d1\u30b9\uff1a -AddHashValuesToDatabaseDialog.okButton.text_2=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306b\u30cf\u30c3\u30b7\u30e5\u3092\u8ffd\u52a0 +AddHashValuesToDatabaseDialog.okButton.text_2=OK From fa8b42c1e7f8c25efb62f6fb76938cde0f442405 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 3 Aug 2018 11:28:18 -0400 Subject: [PATCH 089/105] Cleanup. --- .../sleuthkit/autopsy/report/ReportHTML.java | 46 ++++++++++--------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index 50dfe318c3..b2d388bedc 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java @@ -80,7 +80,6 @@ class ReportHTML implements TableReportModule { private static final int MAX_THUMBS_PER_PAGE = 1000; private static final String HTML_SUBDIR = "content"; private Case currentCase; - private SleuthkitCase skCase; static Integer THUMBNAIL_COLUMNS = 5; private Map dataTypes; @@ -109,7 +108,6 @@ class ReportHTML implements TableReportModule { // Refesh the member variables private void refresh() throws NoCurrentCaseException { currentCase = Case.getCurrentCaseThrows(); - skCase = currentCase.getSleuthkitCase(); dataTypes = new TreeMap<>(); @@ -274,7 +272,7 @@ class ReportHTML implements TableReportModule { in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/accounts.png"); //NON-NLS break; default: - logger.log(Level.WARNING, "useDataTypeIcon: unhandled artifact type = " + dataType); //NON-NLS + logger.log(Level.WARNING, "useDataTypeIcon: unhandled artifact type = {0}", dataType); //NON-NLS in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/star.png"); //NON-NLS iconFileName = "star.png"; //NON-NLS iconFilePath = subPath + File.separator + iconFileName; @@ -627,12 +625,19 @@ class ReportHTML implements TableReportModule { int positionCounter = 0; for (String cell : row) { // position-dependent code used to format this report. Not great, but understandable for formatting. - if (positionCounter == 1) { // Convert the file name to a hyperlink and left-align it - builder.append("\t\t").append(localFileLink.toString()).append(cell).append("\n"); //NON-NLS - } else if (positionCounter == 7) { // Right-align the bytes column. - builder.append("\t\t").append(cell).append("\n"); //NON-NLS - } else { // Regular case, not a file name nor a byte count - builder.append("\t\t").append(cell).append("\n"); //NON-NLS + switch (positionCounter) { + case 1: + // Convert the file name to a hyperlink and left-align it + builder.append("\t\t").append(localFileLink.toString()).append(cell).append("\n"); //NON-NLS + break; + case 7: + // Right-align the bytes column. + builder.append("\t\t").append(cell).append("\n"); //NON-NLS + break; + default: + // Regular case, not a file name nor a byte count + builder.append("\t\t").append(cell).append("\n"); //NON-NLS + break; } ++positionCounter; } @@ -719,7 +724,7 @@ class ReportHTML implements TableReportModule { for (int i = 0; i < tags.size(); i++) { ContentTag tag = tags.get(i); String notableString = tag.getName().getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; - linkToThumbnail.append(tag.getName().getDisplayName() + notableString); + linkToThumbnail.append(tag.getName().getDisplayName()).append(notableString); if (i != tags.size() - 1) { linkToThumbnail.append(", "); } @@ -751,12 +756,9 @@ class ReportHTML implements TableReportModule { return true; } AbstractFile file = (AbstractFile) c; - if (file.isDir() + return file.isDir() || file.getType() == TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS - || file.getType() == TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) { - return true; - } - return false; + || file.getType() == TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS; } /** @@ -1052,9 +1054,9 @@ class ReportHTML implements TableReportModule { * Write the summary of the current case for this report. */ private void writeSummary() { - Writer out = null; + Writer output = null; try { - out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(subPath + "summary.html"), "UTF-8")); //NON-NLS + output = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(subPath + "summary.html"), "UTF-8")); //NON-NLS StringBuilder head = new StringBuilder(); head.append("\n\n").append( //NON-NLS NbBundle.getMessage(this.getClass(), "ReportHTML.writeSum.title")).append("\n"); //NON-NLS @@ -1080,7 +1082,7 @@ class ReportHTML implements TableReportModule { head.append("li {padding-bottom: 5px;}"); head.append("\n"); //NON-NLS head.append("\n\n"); //NON-NLS - out.write(head.toString()); + output.write(head.toString()); DateFormat datetimeFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); Date date = new Date(); @@ -1119,7 +1121,7 @@ class ReportHTML implements TableReportModule { } summary.append("\n"); //NON-NLS summary.append(""); //NON-NLS - out.write(summary.toString()); + output.write(summary.toString()); } catch (FileNotFoundException ex) { logger.log(Level.SEVERE, "Could not find summary.html file to write to."); //NON-NLS } catch (UnsupportedEncodingException ex) { @@ -1130,9 +1132,9 @@ class ReportHTML implements TableReportModule { logger.log(Level.WARNING, "Unable to get current sleuthkit Case for the HTML report."); } finally { try { - if (out != null) { - out.flush(); - out.close(); + if (output != null) { + output.flush(); + output.close(); } } catch (IOException ex) { } From 9c4f2b24385f03f84ec0d652c0b717d45523f698 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 3 Aug 2018 14:23:11 -0400 Subject: [PATCH 090/105] Normalize path. --- .../sleuthkit/autopsy/report/ReportHTML.java | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index b2d388bedc..81c4c9ac72 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java @@ -784,8 +784,14 @@ class ReportHTML implements TableReportModule { localFileFolder.mkdirs(); } - // Construct a file tagName for the local file that incorporates the file id to ensure uniqueness. - String fileName = file.getName(); + /* + * Construct a file tagName for the local file that incorporates the + * file ID to ensure uniqueness. + * + * Note: File name is normalized to account for possible attribute name + * which will be separated by a ':' character. + */ + String fileName = org.sleuthkit.autopsy.coreutils.FileUtil.escapeFileName(file.getName()); String objectIdSuffix = "_" + file.getId(); int lastDotIndex = fileName.lastIndexOf("."); if (lastDotIndex != -1 && lastDotIndex != 0) { @@ -1294,9 +1300,24 @@ class ReportHTML implements TableReportModule { return summary; } + /** + * Create a thumbnail of a given file. + * + * @param file The file from which to create the thumbnail. + * + * @return The path to the thumbnail file, or null if a thumbnail couldn't + * be created. + */ private String prepareThumbnail(AbstractFile file) { BufferedImage bufferedThumb = ImageUtils.getThumbnail(file, ImageUtils.ICON_SIZE_MEDIUM); - File thumbFile = Paths.get(thumbsPath, file.getName() + ".png").toFile(); + + /* + * File name is normalized to account for possible attribute name which + * will be separated by a ':' character. + */ + String fileName = org.sleuthkit.autopsy.coreutils.FileUtil.escapeFileName(file.getName()); + + File thumbFile = Paths.get(thumbsPath, fileName + ".png").toFile(); if (bufferedThumb == null) { return null; } From 19b7ba19c0b3a160fcaca535af0a1a052ceac264 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 3 Aug 2018 16:15:27 -0400 Subject: [PATCH 091/105] 4103 added icons back to AID 2.0 as part of figuring out how to do 4095 --- .../guiutils/StatusIconCellRenderer.java | 32 ++++++++++++----- .../autoingest/AutoIngestJobsNode.java | 2 +- .../autoingest/AutoIngestJobsPanel.java | 3 ++ .../PrioritizedIconCellRenderer.java | 35 +++++++++++++------ 4 files changed, 51 insertions(+), 21 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/guiutils/StatusIconCellRenderer.java b/Core/src/org/sleuthkit/autopsy/guiutils/StatusIconCellRenderer.java index 15c1e0adf4..02874440f7 100644 --- a/Core/src/org/sleuthkit/autopsy/guiutils/StatusIconCellRenderer.java +++ b/Core/src/org/sleuthkit/autopsy/guiutils/StatusIconCellRenderer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015-2017 Basis Technology Corp. + * Copyright 2015-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,16 +19,19 @@ package org.sleuthkit.autopsy.guiutils; import java.awt.Component; +import java.lang.reflect.InvocationTargetException; import javax.swing.ImageIcon; import javax.swing.JTable; import static javax.swing.SwingConstants.CENTER; +import org.openide.nodes.Node; import org.openide.util.ImageUtilities; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.datamodel.NodeProperty; /** - * A JTable cell renderer that represents a status as a center-aligned icon, and - * grays out the cell if the table is disabled. The statuses represented are OK, - * WARNING, and ERROR. + * A JTable and outline view cell renderer that represents a status as a + * center-aligned icon, and grays out the cell if the table is disabled. The + * statuses represented are OK, WARNING, and ERROR. */ public class StatusIconCellRenderer extends GrayableCellRenderer { @@ -45,8 +48,20 @@ public class StatusIconCellRenderer extends GrayableCellRenderer { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { setHorizontalAlignment(CENTER); - if ((value instanceof Status)) { - switch((Status) value) { + Object switchValue = null; + if ((value instanceof NodeProperty)) { + //The Outline view has properties in the cell, the value contained in the property is what we want + try { + switchValue = ((Node.Property) value).getValue(); + } catch (IllegalAccessException | InvocationTargetException ex) { + //Unable to get the value from the NodeProperty no Icon will be displayed + } + } else { + //JTables contain the value we want directly in the cell + switchValue = value; + } + if ((switchValue instanceof Status)) { + switch ((Status) switchValue) { case OK: setIcon(OK_ICON); setToolTipText(org.openide.util.NbBundle.getMessage(StatusIconCellRenderer.class, "StatusIconCellRenderer.tooltiptext.ok")); @@ -60,8 +75,7 @@ public class StatusIconCellRenderer extends GrayableCellRenderer { setToolTipText(org.openide.util.NbBundle.getMessage(StatusIconCellRenderer.class, "StatusIconCellRenderer.tooltiptext.error")); break; } - } - else { + } else { setIcon(null); setText(""); } @@ -69,7 +83,7 @@ public class StatusIconCellRenderer extends GrayableCellRenderer { return this; } - + public enum Status { OK, WARNING, diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java index d5bfbd13d8..00a2bc4d37 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java @@ -326,7 +326,7 @@ final class AutoIngestJobsNode extends AbstractNode { ss.put(new NodeProperty<>(Bundle.AutoIngestJobsNode_jobCreated_text(), Bundle.AutoIngestJobsNode_jobCreated_text(), Bundle.AutoIngestJobsNode_jobCreated_text(), jobWrapper.getManifest().getDateFileCreated())); ss.put(new NodeProperty<>(Bundle.AutoIngestJobsNode_priority_text(), Bundle.AutoIngestJobsNode_priority_text(), Bundle.AutoIngestJobsNode_priority_text(), - jobWrapper.getPriority() > 0 ? Bundle.AutoIngestJobsNode_prioritized_true() : Bundle.AutoIngestJobsNode_prioritized_false())); + jobWrapper.getPriority())); break; case RUNNING_JOB: AutoIngestJob.StageDetails status = jobWrapper.getProcessingStageDetails(); diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java index fb6f79ab0c..18fb8171b2 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java @@ -31,6 +31,7 @@ import org.sleuthkit.autopsy.datamodel.EmptyNode; import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestJobsNode.AutoIngestJobStatus; import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestJobsNode.JobNode; import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestNodeRefreshEvents.AutoIngestRefreshEvent; +import org.sleuthkit.autopsy.guiutils.StatusIconCellRenderer; /** * A panel which displays an outline view with all jobs for a specified status. @@ -84,6 +85,7 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa indexOfColumn = getColumnIndexByName(Bundle.AutoIngestJobsNode_priority_text()); if (indexOfColumn != INVALID_INDEX) { outline.getColumnModel().getColumn(indexOfColumn).setPreferredWidth(INITIAL_PRIORITIZED_WIDTH); + outline.getColumnModel().getColumn(indexOfColumn).setCellRenderer(new PrioritizedIconCellRenderer()); } break; case RUNNING_JOB: @@ -108,6 +110,7 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa indexOfColumn = getColumnIndexByName(Bundle.AutoIngestJobsNode_status_text()); if (indexOfColumn != INVALID_INDEX) { outline.getColumnModel().getColumn(indexOfColumn).setPreferredWidth(INITIAL_STATUS_WIDTH); + outline.getColumnModel().getColumn(indexOfColumn).setCellRenderer(new StatusIconCellRenderer()); } break; default: diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizedIconCellRenderer.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizedIconCellRenderer.java index a4066e6c15..a41e3c0d6d 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizedIconCellRenderer.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizedIconCellRenderer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2017 Basis Technology Corp. + * Copyright 2017-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,21 +19,22 @@ package org.sleuthkit.autopsy.experimental.autoingest; import java.awt.Component; +import java.lang.reflect.InvocationTargetException; import javax.swing.ImageIcon; import javax.swing.JTable; import static javax.swing.SwingConstants.CENTER; +import org.openide.nodes.Node; import org.openide.util.ImageUtilities; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.guiutils.GrayableCellRenderer; -import org.sleuthkit.autopsy.guiutils.StatusIconCellRenderer; +import org.sleuthkit.autopsy.datamodel.NodeProperty; /** - * A JTable cell renderer that represents whether the priority value of a job - * has ever been increased, tick if prioritized nothing if not. + * A JTable and Outline view cell renderer that represents whether the priority + * value of a job has ever been increased, tick if prioritized nothing if not. */ class PrioritizedIconCellRenderer extends GrayableCellRenderer { - @Messages({ "PrioritizedIconCellRenderer.prioritized.tooltiptext=This job has been prioritized. The most recently prioritized job should be processed next.", "PrioritizedIconCellRenderer.notPrioritized.tooltiptext=This job has not been prioritized." @@ -44,13 +45,25 @@ class PrioritizedIconCellRenderer extends GrayableCellRenderer { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { setHorizontalAlignment(CENTER); - if ((value instanceof Integer)) { - if ((int) value == 0) { - setIcon(null); + Object switchValue = null; + if ((value instanceof NodeProperty)) { + //The Outline view has properties in the cell, the value contained in the property is what we want + try { + switchValue = ((Node.Property) value).getValue(); + } catch (IllegalAccessException | InvocationTargetException ignored) { + //Unable to get the value from the NodeProperty no Icon will be displayed + } + } else { + //JTables contain the value we want directly in the cell + switchValue = value; + } + if (switchValue instanceof Integer && (int) switchValue != 0) { + setIcon(checkedIcon); + setToolTipText(org.openide.util.NbBundle.getMessage(PrioritizedIconCellRenderer.class, "PrioritizedIconCellRenderer.prioritized.tooltiptext")); + } else { + setIcon(null); + if (switchValue instanceof Integer) { setToolTipText(org.openide.util.NbBundle.getMessage(PrioritizedIconCellRenderer.class, "PrioritizedIconCellRenderer.notPrioritized.tooltiptext")); - } else { - setIcon(checkedIcon); - setToolTipText(org.openide.util.NbBundle.getMessage(PrioritizedIconCellRenderer.class, "PrioritizedIconCellRenderer.prioritized.tooltiptext")); } } grayCellIfTableNotEnabled(table, isSelected); From 833da054843bc6595543cf710615c91f9f39a85c Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 3 Aug 2018 17:27:46 -0400 Subject: [PATCH 092/105] 3964 update url for new version of Emedded test file --- Core/build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/build.xml b/Core/build.xml index aa654b0f36..2efe03ecea 100644 --- a/Core/build.xml +++ b/Core/build.xml @@ -86,7 +86,7 @@ - + From c6db99e3dd747b90eccecc36c1b2a150837115ef Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Mon, 6 Aug 2018 13:36:40 -0400 Subject: [PATCH 093/105] Implemented suggested changes from PR review --- .../autopsy/contentviewers/SQLiteViewer.java | 131 ++++----- .../autopsy/sqlitereader/SQLiteReader.java | 249 ++++++++++++------ 2 files changed, 235 insertions(+), 145 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java index eb07dfd271..6988e46527 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java @@ -22,8 +22,9 @@ import java.awt.BorderLayout; import java.awt.Component; import java.awt.Cursor; import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; -import java.sql.Connection; import java.sql.SQLException; import java.util.Arrays; import java.util.Collections; @@ -31,6 +32,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.logging.Level; +import java.util.stream.Collectors; import javax.swing.JComboBox; import javax.swing.JFileChooser; import javax.swing.JOptionPane; @@ -40,15 +42,11 @@ import org.openide.util.NbBundle; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.casemodule.services.FileManager; -import org.sleuthkit.autopsy.casemodule.services.Services; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; -import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.autopsy.sqlitereader.SQLiteReader; -import org.sleuthkit.datamodel.SleuthkitCase; /** * A file content viewer for SQLite database files. @@ -63,7 +61,7 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { private final SQLiteTableView selectedTableView = new SQLiteTableView(); private AbstractFile sqliteDbFile; private File tmpDbFile; - private Connection connection; + private SQLiteReader sqliteReader; private int numRows; // num of rows in the selected table private int currPage = 0; // curr page of rows being displayed @@ -340,10 +338,10 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { numEntriesField.setText(""); // close DB connection to file - if (null != connection) { + if (null != sqliteReader) { try { - connection.close(); - connection = null; + sqliteReader.close(); + sqliteReader = null; } catch (SQLException ex) { logger.log(Level.SEVERE, "Failed to close DB connection to file.", ex); //NON-NLS } @@ -365,14 +363,12 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { "# {0} - exception message", "SQLiteViewer.errorMessage.unexpectedError=An unexpected error occurred:\n{0).",}) private void processSQLiteFile() { tablesDropdownList.removeAllItems(); - try { - String tmpDBPathName = Case.getCurrentCaseThrows().getTempDirectory() + + String localDiskPath = Case.getCurrentCaseThrows().getTempDirectory() + File.separator + sqliteDbFile.getName(); - moveDbToTempFile(sqliteDbFile, tmpDBPathName); + sqliteReader = new SQLiteReader(sqliteDbFile, localDiskPath); - connection = SQLiteReader.getDatabaseConnection(tmpDBPathName); - Map dbTablesMap = SQLiteReader.getTableNameAndSchemaPairs(connection); + Map dbTablesMap = sqliteReader.getTableSchemas(); if (dbTablesMap.isEmpty()) { tablesDropdownList.addItem(Bundle.SQLiteViewer_comboBox_noTableEntry()); @@ -411,7 +407,7 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { }) private void selectTable(String tableName) { try { - numRows = SQLiteReader.getTableRowCount(connection, tableName); + numRows = sqliteReader.getTableRowCount(tableName); numEntriesField.setText(numRows + " entries"); currPage = 1; @@ -444,8 +440,8 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { private void readTable(String tableName, int startRow, int numRowsToRead) { try { - List> rows = SQLiteReader.getRowsFromTable( - connection, tableName, startRow, numRowsToRead); + List> rows = sqliteReader.getRowsFromTable( + tableName, startRow, numRowsToRead); if (Objects.nonNull(rows)) { selectedTableView.setupTable(rows); } else { @@ -460,22 +456,65 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { } } - @NbBundle.Messages({"SQLiteViewer.exportTableToCsv.write.errText=Failed to export table content to csv file.", - "SQLiteViewer.exportTableToCsv.FileName=File name: ", - "SQLiteViewer.exportTableToCsv.TableName=Table name: " + /** + * Converts a sqlite table into a CSV file. + * + * @param file + * @param tableName + * @param rowMap -- A list of rows in the table, where each row is represented as a column-value + * map. + * @throws FileNotFoundException + * @throws IOException + */ + @NbBundle.Messages({ + "SQLiteViewer.exportTableToCsv.FileName=File name: ", + "SQLiteViewer.exportTableToCsv.TableName=Table name: " + }) + public void exportTableToCSV(File file, String tableName, + List> rowMap) throws FileNotFoundException, IOException{ + + File csvFile; + String fileName = file.getName(); + if (FilenameUtils.getExtension(fileName).equalsIgnoreCase("csv")) { + csvFile = file; + } else { + csvFile = new File(file.toString() + ".csv"); + } + + try (FileOutputStream out = new FileOutputStream(csvFile, false)) { + + out.write((Bundle.SQLiteViewer_exportTableToCsv_FileName() + csvFile.getName() + "\n").getBytes()); + out.write((Bundle.SQLiteViewer_exportTableToCsv_TableName() + tableName + "\n").getBytes()); + + String header = createColumnHeader(rowMap.get(0)).concat("\n"); + out.write(header.getBytes()); + + for (Map maps : rowMap) { + String row = maps.values() + .stream() + .map(Object::toString) + .collect(Collectors.joining(",")) + .concat("\n"); + out.write(row.getBytes()); + } + } + } + + @NbBundle.Messages({ + "SQLiteViewer.exportTableToCsv.write.errText=Failed to export table content to csv file.", }) private void exportTableToCsv(File file) { String tableName = (String) this.tablesDropdownList.getSelectedItem(); try { List> currentTableRows = - SQLiteReader.getRowsFromTable(connection, tableName); + sqliteReader.getRowsFromTable(tableName); if (Objects.isNull(currentTableRows) || currentTableRows.isEmpty()) { logger.log(Level.INFO, String.format( "The table %s is empty. (objId=%d)", tableName, //NON-NLS sqliteDbFile.getId())); } else { - SQLiteReader.exportTableToCSV(file, tableName, currentTableRows); + exportTableToCSV(file, tableName, currentTableRows); } } catch (SQLException ex) { logger.log(Level.SEVERE, String.format( @@ -491,45 +530,17 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { } } - private static void moveDbToTempFile(AbstractFile sqliteDbFile, String tempDbPath) - throws IOException, NoCurrentCaseException, TskCoreException { - - File tmpDbFile = new File(tempDbPath); - if (!tmpDbFile.exists()) { - ContentUtils.writeToFile(sqliteDbFile, tmpDbFile); - - // Look for any meta files associated with this DB - WAL, SHM, etc. - findAndCopySQLiteMetaFile(sqliteDbFile, sqliteDbFile.getName() + "-wal"); - findAndCopySQLiteMetaFile(sqliteDbFile, sqliteDbFile.getName() + "-shm"); - } - } - /** - * Searches for a meta file associated with the give SQLite db If found, - * copies the file to the temp folder - * - * @param sqliteFile - SQLIte db file being processed - * @param metaFileName name of meta file to look for + * Returns a comma seperated header string from the keys of the column + * row map. + * + * @param row -- column header row map + * @return -- comma seperated header string */ - private static void findAndCopySQLiteMetaFile(AbstractFile sqliteFile, - String metaFileName) throws NoCurrentCaseException, TskCoreException, IOException { - - Case openCase = Case.getCurrentCaseThrows(); - SleuthkitCase sleuthkitCase = openCase.getSleuthkitCase(); - Services services = new Services(sleuthkitCase); - FileManager fileManager = services.getFileManager(); - - List metaFiles = fileManager.findFiles( - sqliteFile.getDataSource(), metaFileName, - sqliteFile.getParent().getName()); - - if (metaFiles != null) { - for (AbstractFile metaFile : metaFiles) { - String tmpMetafilePathName = openCase.getTempDirectory() + - File.separator + metaFile.getName(); - File tmpMetafile = new File(tmpMetafilePathName); - ContentUtils.writeToFile(metaFile, tmpMetafile); - } - } + private String createColumnHeader(Map row) { + return row.entrySet() + .stream() + .map(Map.Entry::getKey) + .collect(Collectors.joining(",")); } } diff --git a/Core/src/org/sleuthkit/autopsy/sqlitereader/SQLiteReader.java b/Core/src/org/sleuthkit/autopsy/sqlitereader/SQLiteReader.java index 90a63ad0eb..969d7c53fa 100755 --- a/Core/src/org/sleuthkit/autopsy/sqlitereader/SQLiteReader.java +++ b/Core/src/org/sleuthkit/autopsy/sqlitereader/SQLiteReader.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-2018 Basis Technology Corp. + * Copyright 2018-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,8 +19,6 @@ package org.sleuthkit.autopsy.sqlitereader; import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.IOException; import java.sql.Connection; import java.sql.DriverManager; @@ -33,34 +31,123 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; -import java.util.stream.Collectors; -import org.apache.commons.io.FilenameUtils; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.casemodule.services.FileManager; +import org.sleuthkit.autopsy.casemodule.services.Services; +import org.sleuthkit.autopsy.datamodel.ContentUtils; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TskCoreException; /** - * Abstracts the need to open (and close) statements and result sets from the - * JDBC. Classes using the SQLiteExtractor must maintain a reference to the - * Connection object generated in getDatabaseConnection. + * Reads rows from SQLite tables and returns results in a list collection. */ -public final class SQLiteReader { +public class SQLiteReader implements AutoCloseable { - private SQLiteReader(){} + private final Connection connection; + + /** + * Writes data source file contents to local disk and opens a sqlite JDBC + * connection. + * + * @param sqliteDbFile -- Data source abstract file + * @param localDiskPath -- Location for database contents to be copied to + * @throws ClassNotFoundException -- missing SQLite JDBC class + * @throws SQLException -- Exception opening JDBC connection + * @throws IOException -- Exception writing file contents + * @throws NoCurrentCaseException -- Current case closed during file copying + * @throws TskCoreException -- Exception finding files from abstract file + */ + public SQLiteReader(AbstractFile sqliteDbFile, String localDiskPath) throws ClassNotFoundException, + SQLException, IOException, NoCurrentCaseException, TskCoreException{ + + writeDataSourceToLocalDisk(sqliteDbFile, localDiskPath); + connection = getDatabaseConnection(localDiskPath); + } + + /** + * Copies the data source file contents to local drive for processing. + * + * @param file -- AbstractFile from the data source + * @param localDiskPath -- Local drive path to copy AbstractFile contents + * @throws IOException -- Exception writing file contents + * @throws NoCurrentCaseException -- Current case closed during file copying + * @throws TskCoreException -- Exception finding files from abstract file + */ + private void writeDataSourceToLocalDisk(AbstractFile file, String localDiskPath) + throws IOException, NoCurrentCaseException, TskCoreException { + + File localDatabaseFile = new File(localDiskPath); + if (!localDatabaseFile.exists()) { + ContentUtils.writeToFile(file, localDatabaseFile); - public static Connection getDatabaseConnection(String dbPath) + // Look for any meta files associated with this DB - WAL, SHM, etc. + findAndCopySQLiteMetaFile(file, file.getName() + "-wal"); + findAndCopySQLiteMetaFile(file, file.getName() + "-shm"); + } + } + + /** + * Searches for a meta file associated with the give SQLite database. If found, + * copies the file to the local disk folder + * + * @param sqliteFile -- SQLIte db file being processed + * @param metaFileName -- name of meta file to look for + * @throws NoCurrentCaseException -- Case has been closed. + * @throws TskCoreException -- fileManager cannot find AbstractFile files. + * @throws IOException -- Issue during writing to file. + */ + private void findAndCopySQLiteMetaFile(AbstractFile sqliteFile, + String metaFileName) throws NoCurrentCaseException, TskCoreException, IOException { + + Case openCase = Case.getCurrentCaseThrows(); + SleuthkitCase sleuthkitCase = openCase.getSleuthkitCase(); + Services services = new Services(sleuthkitCase); + FileManager fileManager = services.getFileManager(); + + List metaFiles = fileManager.findFiles( + sqliteFile.getDataSource(), metaFileName, + sqliteFile.getParent().getName()); + + if (metaFiles != null) { + for (AbstractFile metaFile : metaFiles) { + String tmpMetafilePathName = openCase.getTempDirectory() + + File.separator + metaFile.getName(); + File tmpMetafile = new File(tmpMetafilePathName); + ContentUtils.writeToFile(metaFile, tmpMetafile); + } + } + } + + /** + * Opens a JDBC connection to the sqlite database specified by the path + * parameter. + * + * @param databasePath -- Local path of sqlite database + * @return Connection -- JDBC connection, to be maintained and closed by the reader + * @throws ClassNotFoundException -- missing SQLite JDBC class + * @throws SQLException -- Exception during opening database connection + */ + private Connection getDatabaseConnection(String databasePath) throws ClassNotFoundException, SQLException { // Load the SQLite JDBC driver, if necessary. Class.forName("org.sqlite.JDBC"); //NON-NLS return DriverManager.getConnection( - "jdbc:sqlite:" + dbPath); //NON-NLS + "jdbc:sqlite:" + databasePath); //NON-NLS } - /** - * Gets the table names and schemas from the SQLite database file. - * - * @return A mapping of table names to SQL CREATE TABLE statements. + /** + * Retrieves a map view of table names to table schemas (in the form of + * CREATE TABLE statments). + * + * @return Map -- A map of table names to table schemas + * @throws SQLException -- occurs if resultSet is closed while attempting to + * getString() or next(). */ - public static Map getTableNameAndSchemaPairs(Connection connection) + public Map getTableSchemas() throws SQLException { Map dbTablesMap = new TreeMap<>(); @@ -81,95 +168,82 @@ public final class SQLiteReader { return dbTablesMap; } - public static Integer getTableRowCount(Connection connection, - String tableName) throws SQLException { + /** + * Retrieves the total number of rows from a table in the SQLite database. + * + * @param tableName + * @return Integer -- row count from tableName + * @throws SQLException -- occurs if ResultSet is closed before calling getInt(). + */ + public Integer getTableRowCount(String tableName) throws SQLException { try (Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery( - "SELECT count (*) as count FROM " + tableName)){ - return resultSet.getInt("count"); + "SELECT count (*) as count FROM " + tableName)){ //NON-NLS + return resultSet.getInt("count"); //NON-NLS } } - public static List> getRowsFromTable(Connection connection, - String tableName) throws SQLException { + /** + * Retrieves all rows from a given table in the SQLite database. If only a + * subset of rows are desired, see the overloaded function below. + * + * @param tableName + * @return List> -- List of rows, where each row is + * represented as a column-value map. + * @throws SQLException -- occurs if ResultSet is closed before being used in + * resultSetToList function. + */ + public List> getRowsFromTable(String tableName) throws SQLException { + + //This method does not directly call its overloaded counterpart + //since the second parameter would need to be retreived from a call to + //getTableRowCount(). try(Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery( - "SELECT * FROM " + tableName)) { + "SELECT * FROM " + tableName)) { //NON-NLS return resultSetToList(resultSet); } } - @NbBundle.Messages({"# {0} - tableName", - "SQLiteExtractor.readTable.errorText=Error getting rows for table: {0}"}) - public static List> getRowsFromTable(Connection connection, String tableName, + /** + * Retrieves a subset of the rows from a given table in the SQLite database. + * + * @param tableName + * @param startRow -- Desired start index (rows begin at 1) + * @param numRowsToRead -- Number of rows past the start index + * @return List> -- List of rows, where each row is + * represented as a column-value map. + * @throws SQLException -- occurs if ResultSet is closed before being used in + * resultSetToList function. + */ + public List> getRowsFromTable(String tableName, int startRow, int numRowsToRead) throws SQLException{ try(Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery( - "SELECT * FROM " + tableName - + " LIMIT " + Integer.toString(numRowsToRead) - + " OFFSET " + Integer.toString(startRow - 1))) { + "SELECT * FROM " + tableName //NON-NLS + + " LIMIT " + Integer.toString(numRowsToRead) //NON-NLS + + " OFFSET " + Integer.toString(startRow - 1))) { //NON-NLS return resultSetToList(resultSet); } } - @NbBundle.Messages({"SQLiteExtractor.exportTableToCsv.write.errText=Failed to export table content to csv file.", - "SQLiteExtractor.exportTableToCsv.FileName=File name: ", - "SQLiteExtractor.exportTableToCsv.TableName=Table name: " - }) - public static void exportTableToCSV(File file, String tableName, - List> keyValuePairsInRows) throws FileNotFoundException, IOException{ - - File csvFile; - String fileName = file.getName(); - if (FilenameUtils.getExtension(fileName).equalsIgnoreCase("csv")) { - csvFile = file; - } else { - csvFile = new File(file.toString() + ".csv"); - } - - try (FileOutputStream out = new FileOutputStream(csvFile, false)) { - - out.write((Bundle.SQLiteExtractor_exportTableToCsv_FileName() + csvFile.getName() + "\n").getBytes()); - out.write((Bundle.SQLiteExtractor_exportTableToCsv_TableName() + tableName + "\n").getBytes()); - - String header = createColumnHeader(keyValuePairsInRows.get(0)).concat("\n"); - out.write(header.getBytes()); - - for (Map maps : keyValuePairsInRows) { - String row = maps.values() - .stream() - .map(Object::toString) - .collect(Collectors.joining(",")) - .concat("\n"); - out.write(row.getBytes()); - } - } - } - - public static void exportTableToCSV(File file, String tableName, - ResultSet resultSet) throws SQLException, IOException { - exportTableToCSV(file, tableName, resultSetToList(resultSet)); - } - - private static String createColumnHeader(Map row) { - - return row.entrySet() - .stream() - .map(Map.Entry::getKey) - .collect(Collectors.joining(",")); - } - /** - * The map holds the column name to value pairs for a particular row. For example, (id, 123) - * is a valid key-value pair in the map. + * Converts a ResultSet (row results from a table read) and converts + * them into a collection view. + * + * @param resultSet -- row results from a table read + * @return List> -- List of rows, where each row is + * represented as a column-value map. + * @throws SQLException -- occurs if ResultSet is closed while attempting to + * access it's data. */ - @NbBundle.Messages("SQLiteExtractor.BlobNotShown.message=BLOB Data not shown") - private static List> resultSetToList(ResultSet resultSet) throws SQLException { + @NbBundle.Messages("SQLiteReader.BlobNotShown.message=BLOB Data not shown") + private List> resultSetToList(ResultSet resultSet) throws SQLException { ResultSetMetaData metaData = resultSet.getMetaData(); int columns = metaData.getColumnCount(); - List> keyValuePairsInRows = new ArrayList<>(); + List> rowMap = new ArrayList<>(); while (resultSet.next()) { Map row = new LinkedHashMap<>(columns); for (int i = 1; i <= columns; ++i) { @@ -177,15 +251,20 @@ public final class SQLiteReader { row.put(metaData.getColumnName(i), ""); } else { if (metaData.getColumnTypeName(i).compareToIgnoreCase("blob") == 0) { - row.put(metaData.getColumnName(i), Bundle.SQLiteExtractor_BlobNotShown_message()); + row.put(metaData.getColumnName(i), Bundle.SQLiteReader_BlobNotShown_message()); } else { row.put(metaData.getColumnName(i), resultSet.getObject(i)); } } } - keyValuePairsInRows.add(row); + rowMap.add(row); } - return keyValuePairsInRows; + return rowMap; + } + + @Override + public void close() throws SQLException { + connection.close(); } } From d516660aa3e6deeb65d08dab30c468dd9a750737 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Mon, 6 Aug 2018 13:39:34 -0400 Subject: [PATCH 094/105] Fixed param and return type comment headers --- .../autopsy/sqlitereader/SQLiteReader.java | 72 +++++++++---------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/sqlitereader/SQLiteReader.java b/Core/src/org/sleuthkit/autopsy/sqlitereader/SQLiteReader.java index 969d7c53fa..1787577d29 100755 --- a/Core/src/org/sleuthkit/autopsy/sqlitereader/SQLiteReader.java +++ b/Core/src/org/sleuthkit/autopsy/sqlitereader/SQLiteReader.java @@ -52,13 +52,13 @@ public class SQLiteReader implements AutoCloseable { * Writes data source file contents to local disk and opens a sqlite JDBC * connection. * - * @param sqliteDbFile -- Data source abstract file - * @param localDiskPath -- Location for database contents to be copied to - * @throws ClassNotFoundException -- missing SQLite JDBC class - * @throws SQLException -- Exception opening JDBC connection - * @throws IOException -- Exception writing file contents - * @throws NoCurrentCaseException -- Current case closed during file copying - * @throws TskCoreException -- Exception finding files from abstract file + * @param sqliteDbFile Data source abstract file + * @param localDiskPath Location for database contents to be copied to + * @throws ClassNotFoundException missing SQLite JDBC class + * @throws SQLException Exception opening JDBC connection + * @throws IOException Exception writing file contents + * @throws NoCurrentCaseException Current case closed during file copying + * @throws TskCoreException Exception finding files from abstract file */ public SQLiteReader(AbstractFile sqliteDbFile, String localDiskPath) throws ClassNotFoundException, SQLException, IOException, NoCurrentCaseException, TskCoreException{ @@ -70,11 +70,11 @@ public class SQLiteReader implements AutoCloseable { /** * Copies the data source file contents to local drive for processing. * - * @param file -- AbstractFile from the data source - * @param localDiskPath -- Local drive path to copy AbstractFile contents - * @throws IOException -- Exception writing file contents - * @throws NoCurrentCaseException -- Current case closed during file copying - * @throws TskCoreException -- Exception finding files from abstract file + * @param file AbstractFile from the data source + * @param localDiskPath Local drive path to copy AbstractFile contents + * @throws IOException Exception writing file contents + * @throws NoCurrentCaseException Current case closed during file copying + * @throws TskCoreException Exception finding files from abstract file */ private void writeDataSourceToLocalDisk(AbstractFile file, String localDiskPath) throws IOException, NoCurrentCaseException, TskCoreException { @@ -93,11 +93,11 @@ public class SQLiteReader implements AutoCloseable { * Searches for a meta file associated with the give SQLite database. If found, * copies the file to the local disk folder * - * @param sqliteFile -- SQLIte db file being processed - * @param metaFileName -- name of meta file to look for - * @throws NoCurrentCaseException -- Case has been closed. - * @throws TskCoreException -- fileManager cannot find AbstractFile files. - * @throws IOException -- Issue during writing to file. + * @param sqliteFile SQLIte db file being processed + * @param metaFileName name of meta file to look for + * @throws NoCurrentCaseException Case has been closed. + * @throws TskCoreException fileManager cannot find AbstractFile files. + * @throws IOException Issue during writing to file. */ private void findAndCopySQLiteMetaFile(AbstractFile sqliteFile, String metaFileName) throws NoCurrentCaseException, TskCoreException, IOException { @@ -125,10 +125,10 @@ public class SQLiteReader implements AutoCloseable { * Opens a JDBC connection to the sqlite database specified by the path * parameter. * - * @param databasePath -- Local path of sqlite database - * @return Connection -- JDBC connection, to be maintained and closed by the reader - * @throws ClassNotFoundException -- missing SQLite JDBC class - * @throws SQLException -- Exception during opening database connection + * @param databasePath Local path of sqlite database + * @return Connection JDBC connection, to be maintained and closed by the reader + * @throws ClassNotFoundException missing SQLite JDBC class + * @throws SQLException Exception during opening database connection */ private Connection getDatabaseConnection(String databasePath) throws ClassNotFoundException, SQLException { @@ -139,13 +139,13 @@ public class SQLiteReader implements AutoCloseable { "jdbc:sqlite:" + databasePath); //NON-NLS } + /** * Retrieves a map view of table names to table schemas (in the form of * CREATE TABLE statments). * - * @return Map -- A map of table names to table schemas - * @throws SQLException -- occurs if resultSet is closed while attempting to - * getString() or next(). + * @return A map of table names to table schemas + * @throws SQLException */ public Map getTableSchemas() throws SQLException { @@ -172,8 +172,8 @@ public class SQLiteReader implements AutoCloseable { * Retrieves the total number of rows from a table in the SQLite database. * * @param tableName - * @return Integer -- row count from tableName - * @throws SQLException -- occurs if ResultSet is closed before calling getInt(). + * @return Row count from tableName + * @throws SQLException */ public Integer getTableRowCount(String tableName) throws SQLException { try (Statement statement = connection.createStatement(); @@ -188,10 +188,9 @@ public class SQLiteReader implements AutoCloseable { * subset of rows are desired, see the overloaded function below. * * @param tableName - * @return List> -- List of rows, where each row is + * @return List of rows, where each row is * represented as a column-value map. - * @throws SQLException -- occurs if ResultSet is closed before being used in - * resultSetToList function. + * @throws SQLException */ public List> getRowsFromTable(String tableName) throws SQLException { @@ -209,12 +208,11 @@ public class SQLiteReader implements AutoCloseable { * Retrieves a subset of the rows from a given table in the SQLite database. * * @param tableName - * @param startRow -- Desired start index (rows begin at 1) - * @param numRowsToRead -- Number of rows past the start index - * @return List> -- List of rows, where each row is + * @param startRow Desired start index (rows begin at 1) + * @param numRowsToRead Number of rows past the start index + * @return List of rows, where each row is * represented as a column-value map. - * @throws SQLException -- occurs if ResultSet is closed before being used in - * resultSetToList function. + * @throws SQLException */ public List> getRowsFromTable(String tableName, int startRow, int numRowsToRead) throws SQLException{ @@ -232,10 +230,10 @@ public class SQLiteReader implements AutoCloseable { * Converts a ResultSet (row results from a table read) and converts * them into a collection view. * - * @param resultSet -- row results from a table read - * @return List> -- List of rows, where each row is + * @param resultSet row results from a table read + * @return List of rows, where each row is * represented as a column-value map. - * @throws SQLException -- occurs if ResultSet is closed while attempting to + * @throws SQLException occurs if ResultSet is closed while attempting to * access it's data. */ @NbBundle.Messages("SQLiteReader.BlobNotShown.message=BLOB Data not shown") From 11a2bc3685eff092abcf78da6442b3673b5f169b Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Mon, 6 Aug 2018 13:43:12 -0400 Subject: [PATCH 095/105] Final cleanup of comments --- .../org/sleuthkit/autopsy/sqlitereader/SQLiteReader.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/sqlitereader/SQLiteReader.java b/Core/src/org/sleuthkit/autopsy/sqlitereader/SQLiteReader.java index 1787577d29..34cd2969e7 100755 --- a/Core/src/org/sleuthkit/autopsy/sqlitereader/SQLiteReader.java +++ b/Core/src/org/sleuthkit/autopsy/sqlitereader/SQLiteReader.java @@ -227,8 +227,7 @@ public class SQLiteReader implements AutoCloseable { } /** - * Converts a ResultSet (row results from a table read) and converts - * them into a collection view. + * Converts a ResultSet (row results from a table read) into a list. * * @param resultSet row results from a table read * @return List of rows, where each row is @@ -261,6 +260,11 @@ public class SQLiteReader implements AutoCloseable { return rowMap; } + /** + * Closes underlying JDBC connection. + * + * @throws SQLException + */ @Override public void close() throws SQLException { connection.close(); From da535536750f51f673b5ee55f7f5d132c04a51c8 Mon Sep 17 00:00:00 2001 From: rishwanth1995 Date: Mon, 6 Aug 2018 13:48:23 -0400 Subject: [PATCH 096/105] validate user input in launch_bootable_Script --- unix/launch_script_bootable.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/unix/launch_script_bootable.sh b/unix/launch_script_bootable.sh index 23b6ab7ba3..9223c42661 100644 --- a/unix/launch_script_bootable.sh +++ b/unix/launch_script_bootable.sh @@ -24,7 +24,7 @@ errorLog () { exit 1 } -Verify we can find the script +#Verify we can find the script if [[ -x "$AUTOPSY_BIN" ]]; then infoLog "Autopsy found" else @@ -66,7 +66,11 @@ showAndReadOptions () { echo [$x] "${word}" x=$((x + 1)) done - read option + read -n 1 option + if [[ $option = "" ]] || ! [[ "$option" =~ ^[0-9]+$ ]]; then + echo "Please choose a valid option" + showAndReadOptions + fi } From 99b12cc269dde50989b7b13026b1dbbf5fb8d80e Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Mon, 6 Aug 2018 15:48:15 -0400 Subject: [PATCH 097/105] Added some comments and implemented PR review changes --- .../SevenZipExtractor.java | 37 +++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java index b1a0784648..f4feb54f7b 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java @@ -163,8 +163,12 @@ class SevenZipExtractor { * * @param archiveFile the AbstractFile for the parent archive which * which we are checking - * @param archiveFileItem the current item being extracted from the parent - * archive + * @param inArchive The SevenZip archive currently open for extraction + * + * @param inArchiveItemIndex Index of item inside the SevenZip archive. Each + * file inside an archive is assocaited with a unique + * integer. + * * @param depthMap a concurrent hashmap which keeps track of the * depth of all nested archives, key of objectID * @param escapedFilePath the path to the archiveFileItem which has been @@ -657,7 +661,7 @@ class SevenZipExtractor { //According to the documentation, indices in sorted order are optimal //for efficiency. Hence, the LinkedHashMap and linear processing of - //inArchiveItemIndex. + //inArchiveItemIndex. False indicates non-test mode inArchive.extract(extractionIndices, false, archiveCallBack); unpackSuccessful = unpackSuccessful & archiveCallBack.wasSuccessful(); @@ -978,6 +982,18 @@ class SevenZipExtractor { this.password = password; } + /** + * Get stream is called by the internal framework as it traverses + * the archive structure. The ISequentialOutStream is where the + * archive file contents will be expanded and written to the local disk. + * + * Skips folders, as there is nothing to extract. + * + * @param inArchiveItemIndex current location of the + * @param mode Will always be EXTRACT + * @return + * @throws SevenZipException + */ @Override public ISequentialOutStream getStream(int inArchiveItemIndex, ExtractAskMode mode) throws SevenZipException { @@ -1006,6 +1022,13 @@ class SevenZipExtractor { return unpackStream; } + /** + * Retrieves the archive metadata before extraction. Called by the + * internal framework after getStream call for the current index. + * + * @param mode Will always be EXTRACT. + * @throws SevenZipException + */ @Override public void prepareOperation(ExtractAskMode mode) throws SevenZipException { final Date createTime = (Date) inArchive.getProperty( @@ -1024,11 +1047,11 @@ class SevenZipExtractor { } /** - * Pull necessary details from map to appropriately update unpackedNode - * info and provide useful logging messages. This function is called - * after the internal framework has processed the stream. + * Updates the unpackedNode data in the tree, after the archive has been + * expanded to local disk. The map supplies reference to the correct file + * path location and corresponding unpackedNode. * - * @param EOR - ExtractOperationResult + * @param EOR - ExtractOperationResult * * @throws SevenZipException */ From 913891bdf2b53257f4075719df191a64f3159590 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Mon, 6 Aug 2018 15:52:56 -0400 Subject: [PATCH 098/105] Typos and grammar --- .../embeddedfileextractor/SevenZipExtractor.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java index f4feb54f7b..798a05925e 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java @@ -166,8 +166,8 @@ class SevenZipExtractor { * @param inArchive The SevenZip archive currently open for extraction * * @param inArchiveItemIndex Index of item inside the SevenZip archive. Each - * file inside an archive is assocaited with a unique - * integer. + * file inside an archive is associated with a unique + * integer * * @param depthMap a concurrent hashmap which keeps track of the * depth of all nested archives, key of objectID @@ -1023,8 +1023,8 @@ class SevenZipExtractor { } /** - * Retrieves the archive metadata before extraction. Called by the - * internal framework after getStream call for the current index. + * Retrieves the file metadata from the archive before extraction. + * Called after getStream. * * @param mode Will always be EXTRACT. * @throws SevenZipException @@ -1047,9 +1047,8 @@ class SevenZipExtractor { } /** - * Updates the unpackedNode data in the tree, after the archive has been - * expanded to local disk. The map supplies reference to the correct file - * path location and corresponding unpackedNode. + * Updates the unpackedNode data in the tree after the archive has been + * expanded to local disk. * * @param EOR - ExtractOperationResult * From 8a36265b8bbd5ac087723531623d0ba983ba22a3 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 1 Aug 2018 12:33:50 -0400 Subject: [PATCH 099/105] 4088 wrap ReadContentInputStream in BufferedInputStream for mark/reset support --- .../sleuthkit/autopsy/keywordsearch/TextFileExtractor.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TextFileExtractor.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TextFileExtractor.java index bc11515e96..fa2d4dc88b 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TextFileExtractor.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TextFileExtractor.java @@ -17,8 +17,9 @@ * limitations under the License. */ package org.sleuthkit.autopsy.keywordsearch; - import java.io.IOException; +import java.io.InputStream; +import java.io.BufferedInputStream; import java.io.Reader; import java.util.logging.Level; import org.apache.tika.parser.txt.CharsetDetector; @@ -53,7 +54,8 @@ final class TextFileExtractor extends ContentTextExtractor { @Override public Reader getReader(Content source) throws TextExtractorException { CharsetDetector detector = new CharsetDetector(); - ReadContentInputStream stream = new ReadContentInputStream(source); + //wrap stream in a BufferedInputStream so that it supports the mark/reset methods necessary for the CharsetDetector + InputStream stream = new BufferedInputStream(new ReadContentInputStream(source)); try { detector.setText(stream); } catch (IOException ex) { From 715d34a5d13164099fee395f02e72e75f045094e Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 1 Aug 2018 17:38:04 -0400 Subject: [PATCH 100/105] 4088 fix exception messages to reflect current name of TextFileExtractor class --- .../sleuthkit/autopsy/keywordsearch/TextFileExtractor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TextFileExtractor.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TextFileExtractor.java index fa2d4dc88b..b7f3a885b5 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TextFileExtractor.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TextFileExtractor.java @@ -59,11 +59,11 @@ final class TextFileExtractor extends ContentTextExtractor { try { detector.setText(stream); } catch (IOException ex) { - throw new TextExtractorException("Unable to get string from detected text in UnicodeTextExtractor", ex); + throw new TextExtractorException("Unable to get string from detected text in TextFileExtractor", ex); } CharsetMatch match = detector.detect(); if (match.getConfidence() < MIN_MATCH_CONFIDENCE) { - throw new TextExtractorException("Text does not match any character set with a high enough confidence for UnicodeTextExtractor"); + throw new TextExtractorException("Text does not match any character set with a high enough confidence for TextFileExtractor"); } return match.getReader(); From 2832702bccb9488e86e1237aeaf04cbd7431ad84 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 3 Aug 2018 18:02:14 -0400 Subject: [PATCH 101/105] 4088 prevent Carved files from being indexed with the TextFileExtractor --- .../autopsy/keywordsearch/KeywordSearchIngestModule.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java index a8abc03b83..01d95efe53 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java @@ -570,7 +570,9 @@ public final class KeywordSearchIngestModule implements FileIngestModule { putIngestStatus(jobId, aFile.getId(), IngestStatus.SKIPPED_ERROR_TEXTEXTRACT); } - if ((wasTextAdded == false) && (aFile.getNameExtension().equalsIgnoreCase("txt"))) { + if ((wasTextAdded == false) && (aFile.getNameExtension().equalsIgnoreCase("txt") && !(aFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.CARVED)))) { + //Carved Files should be the only type of unallocated files capable of a txt extension and + //should be ignored by the TextFileExtractor because they may contain more than one text encoding try { if (Ingester.getDefault().indexText(txtFileExtractor, aFile, context)) { putIngestStatus(jobId, aFile.getId(), IngestStatus.TEXT_INGESTED); From d7c20b386f23814a70b872653b867a5a2d1c3fc9 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 7 Aug 2018 17:10:37 -0400 Subject: [PATCH 102/105] 4014 clean up files that might be modified to ensure no additional query of tags occurs --- .../actions/GetTagNameAndCommentDialog.java | 23 +++++++---- .../communications/RelationshipNode.java | 6 +-- .../contentviewers/MessageContentViewer.java | 4 +- .../datamodel/AbstractAbstractFileNode.java | 5 --- .../datamodel/AbstractFsContentNode.java | 3 +- .../datamodel/BlackboardArtifactNode.java | 6 +-- .../autopsy/datamodel/LayoutFileNode.java | 38 +++++++++---------- .../autopsy/datamodel/LocalDirectoryNode.java | 4 +- .../autopsy/datamodel/LocalFileNode.java | 4 +- .../datamodel/VirtualDirectoryNode.java | 4 +- 10 files changed, 47 insertions(+), 50 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java index ef7e853d68..cf0c27fb27 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java @@ -24,10 +24,8 @@ import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.logging.Level; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.TreeMap; import javax.swing.AbstractAction; import javax.swing.ActionMap; @@ -57,7 +55,7 @@ public class GetTagNameAndCommentDialog extends JDialog { private final List tagNamesList = new ArrayList<>(); private final List standardTagNamesList = new ArrayList<>(); private TagNameAndComment tagNameAndComment = null; - + public static class TagNameAndComment { private final TagName tagName; @@ -105,7 +103,16 @@ public class GetTagNameAndCommentDialog extends JDialog { public static TagNameAndComment doDialog(Window owner) { GetTagNameAndCommentDialog dialog = new GetTagNameAndCommentDialog(owner); dialog.display(); - return dialog.tagNameAndComment; + return dialog.getTagNameAndComment(); + } + + /** + * Get the TagNameAndComment. + * + * @return the tagNameAndComment + */ + private TagNameAndComment getTagNameAndComment() { + return tagNameAndComment; } private GetTagNameAndCommentDialog(Window owner) { @@ -114,14 +121,14 @@ public class GetTagNameAndCommentDialog extends JDialog { ModalityType.APPLICATION_MODAL); } - private void display() { initComponents(); tagCombo.setRenderer(new DefaultListCellRenderer() { private static final long serialVersionUID = 1L; + @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { - String status = ((TagName) value).getKnownStatus() == TskData.FileKnown.BAD ?TagsManager.getNotableTagLabel() : ""; + String status = ((TagName) value).getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; String newValue = ((TagName) value).getDisplayName() + status; return super.getListCellRendererComponent(list, newValue, index, isSelected, cellHasFocus); } @@ -151,7 +158,7 @@ public class GetTagNameAndCommentDialog extends JDialog { TagsManager tagsManager = Case.getCurrentCaseThrows().getServices().getTagsManager(); List standardTagNames = TagsManager.getStandardTagNames(); Map tagNamesMap = new TreeMap<>(tagsManager.getDisplayNamesToTagNamesMap()); - + tagNamesMap.entrySet().stream().map((entry) -> entry.getValue()).forEachOrdered((tagName) -> { if (standardTagNames.contains(tagName.getDisplayName())) { standardTagNamesList.add(tagName); @@ -159,7 +166,6 @@ public class GetTagNameAndCommentDialog extends JDialog { tagNamesList.add(tagName); } }); - } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(GetTagNameAndCommentDialog.class @@ -320,4 +326,5 @@ public class GetTagNameAndCommentDialog extends JDialog { private javax.swing.JComboBox tagCombo; private javax.swing.JLabel tagLabel; // End of variables declaration//GEN-END:variables + } diff --git a/Core/src/org/sleuthkit/autopsy/communications/RelationshipNode.java b/Core/src/org/sleuthkit/autopsy/communications/RelationshipNode.java index eb448f4f8a..2fd30addcc 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/RelationshipNode.java +++ b/Core/src/org/sleuthkit/autopsy/communications/RelationshipNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2017-18 Basis Technology Corp. + * Copyright 2017-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -46,7 +46,7 @@ import org.sleuthkit.datamodel.TskCoreException; final class RelationshipNode extends BlackboardArtifactNode { private static final Logger logger = Logger.getLogger(RelationshipNode.class.getName()); - + RelationshipNode(BlackboardArtifact artifact) { super(artifact); final String stripEnd = StringUtils.stripEnd(artifact.getDisplayName(), "s"); @@ -115,7 +115,7 @@ final class RelationshipNode extends BlackboardArtifactNode { } addTagProperty(sheetSet); - + return sheet; } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java index 8f08b248fd..a95dd307f5 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java @@ -117,8 +117,8 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont drp.open(); drpExplorerManager = drp.getExplorerManager(); - drpExplorerManager.addPropertyChangeListener(evt -> - viewInNewWindowButton.setEnabled(drpExplorerManager.getSelectedNodes().length == 1)); + drpExplorerManager.addPropertyChangeListener(evt + -> viewInNewWindowButton.setEnabled(drpExplorerManager.getSelectedNodes().length == 1)); } /** diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java index 1a52a61bb2..b4f8f76728 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java @@ -21,14 +21,12 @@ package org.sleuthkit.autopsy.datamodel; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; -import java.util.Arrays; import java.util.EnumSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.stream.Collectors; -import javax.swing.Action; import org.apache.commons.lang3.StringUtils; import org.openide.nodes.Children; import org.openide.nodes.Sheet; @@ -38,9 +36,6 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent; -import org.sleuthkit.autopsy.centralrepository.AddEditCentralRepoCommentAction; -import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil; -import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil; import org.sleuthkit.autopsy.coreutils.Logger; import static org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.AbstractFilePropertyType.*; import static org.sleuthkit.autopsy.datamodel.Bundle.*; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractFsContentNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractFsContentNode.java index b0e33c13bf..824407c417 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractFsContentNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractFsContentNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,6 +29,7 @@ import org.sleuthkit.datamodel.AbstractFile; * Abstract class that implements the commonality between File and Directory * Nodes (same properties). * + * @param extends AbstractFile */ public abstract class AbstractFsContentNode extends AbstractAbstractFileNode { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java index d6fb9afc04..5b20c92c6e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java @@ -48,8 +48,6 @@ import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagAddedEvent; import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagDeletedEvent; import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent; -import org.sleuthkit.autopsy.centralrepository.AddEditCentralRepoCommentAction; -import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import static org.sleuthkit.autopsy.datamodel.DisplayableItemNode.findLinked; @@ -456,10 +454,10 @@ public class BlackboardArtifactNode extends AbstractContentNode 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. @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.LinkedHashMap; @@ -46,11 +47,11 @@ public class LayoutFileNode extends AbstractAbstractFileNode { public static enum LayoutContentPropertyType { PARTS { - @Override - public String toString() { - return NbBundle.getMessage(this.getClass(), "LayoutFileNode.propertyType.parts"); - } - } + @Override + public String toString() { + return NbBundle.getMessage(this.getClass(), "LayoutFileNode.propertyType.parts"); + } + } } public static String nameForLayoutFile(LayoutFile lf) { @@ -115,9 +116,7 @@ public class LayoutFileNode extends AbstractAbstractFileNode { @Override public Action[] getActions(boolean context) { List actionsList = new ArrayList<>(); - for (Action a : super.getActions(true)) { - actionsList.add(a); - } + actionsList.addAll(Arrays.asList(super.getActions(true))); actionsList.add(new NewWindowViewAction( NbBundle.getMessage(this.getClass(), "LayoutFileNode.getActions.viewInNewWin.text"), this)); actionsList.add(new ExternalViewerAction( @@ -126,19 +125,18 @@ public class LayoutFileNode extends AbstractAbstractFileNode { actionsList.add(ExtractAction.getInstance()); actionsList.add(null); // creates a menu separator actionsList.add(AddContentTagAction.getInstance()); - - final Collection selectedFilesList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); - if(selectedFilesList.size() == 1) { + + final Collection selectedFilesList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + if (selectedFilesList.size() == 1) { actionsList.add(DeleteFileContentTagAction.getInstance()); } - + actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList.toArray(new Action[actionsList.size()]); } - - void fillPropertyMap(Map map) { + void fillPropertyMap(Map map) { AbstractAbstractFileNode.fillPropertyMap(map, getContent()); map.put(LayoutContentPropertyType.PARTS.toString(), content.getNumParts()); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LocalDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LocalDirectoryNode.java index 053146daea..9b360763a5 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LocalDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LocalDirectoryNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -40,7 +40,7 @@ public class LocalDirectoryNode extends SpecialDirectoryNode { this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/Folder-icon.png"); //NON-NLS } - + @Override @NbBundle.Messages({ "LocalDirectoryNode.createSheet.name.name=Name", diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java index d5064312b3..00c63b745e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java @@ -96,7 +96,7 @@ public class LocalFileNode extends AbstractAbstractFileNode { public Action[] getActions(boolean context) { List actionsList = new ArrayList<>(); actionsList.addAll(Arrays.asList(super.getActions(true))); - + actionsList.add(new ViewContextAction(NbBundle.getMessage(this.getClass(), "LocalFileNode.viewFileInDir.text"), this.content)); actionsList.add(null); // creates a menu separator actionsList.add(new NewWindowViewAction( @@ -125,7 +125,7 @@ public class LocalFileNode extends AbstractAbstractFileNode { logger.log(Level.WARNING, "Unable to add unzip with password action to context menus", ex); } } - return actionsList.toArray(new Action[0]); + return actionsList.toArray(new Action[actionsList.size()]); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java index 9a7e3eae8e..837a2ae268 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java @@ -50,8 +50,6 @@ public class VirtualDirectoryNode extends SpecialDirectoryNode { this.setDisplayName(nameForVirtualDirectory(ld)); - String name = ld.getName(); - //set icon for name, special case for logical file set if (ld.isDataSource()) { this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/fileset-icon-16.png"); //NON-NLS @@ -59,7 +57,7 @@ public class VirtualDirectoryNode extends SpecialDirectoryNode { this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/folder-icon-virtual.png"); //TODO NON-NLS } } - + @Override @NbBundle.Messages({"VirtualDirectoryNode.createSheet.size.name=Size (Bytes)", "VirtualDirectoryNode.createSheet.size.displayName=Size (Bytes)", From 6fd7482e6e52e2cd64b810fe2c8cce512b4d5be3 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 7 Aug 2018 17:37:39 -0400 Subject: [PATCH 103/105] 4014 clean up files that might be modified to determine the presence of CR comments --- .../DataContentViewerOtherCases.java | 37 ++++++++++++++++--- ...DataContentViewerOtherCasesTableModel.java | 8 ++-- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java index 6579b15e08..9aa77e19a0 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java @@ -922,7 +922,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi * Used as a key to ensure we eliminate duplicates from the result set by * not overwriting CR correlation instances. */ - static final class UniquePathKey { + private static final class UniquePathKey { private final String dataSourceID; private final String filePath; @@ -943,9 +943,9 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi public boolean equals(Object other) { if (other instanceof UniquePathKey) { UniquePathKey otherKey = (UniquePathKey) (other); - return (Objects.equals(otherKey.dataSourceID, this.dataSourceID) - && Objects.equals(otherKey.filePath, this.filePath) - && Objects.equals(otherKey.type, this.type)); + return (Objects.equals(otherKey.getDataSourceID(), this.getDataSourceID()) + && Objects.equals(otherKey.getFilePath(), this.getFilePath()) + && Objects.equals(otherKey.getType(), this.getType())); } return false; } @@ -955,7 +955,34 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi //int hash = 7; //hash = 67 * hash + this.dataSourceID.hashCode(); //hash = 67 * hash + this.filePath.hashCode(); - return Objects.hash(dataSourceID, filePath, type); + return Objects.hash(getDataSourceID(), getFilePath(), getType()); + } + + /** + * Get the type of this UniquePathKey. + * + * @return the type + */ + String getType() { + return type; + } + + /** + * Get the file path for the UniquePathKey. + * + * @return the filePath + */ + String getFilePath() { + return filePath; + } + + /** + * Get the data source id for the UniquePathKey. + * + * @return the dataSourceID + */ + String getDataSourceID() { + return dataSourceID; } } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java index 1f04f1f478..1a3527d940 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java @@ -28,6 +28,8 @@ import org.openide.util.NbBundle.Messages; */ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel { + private static final long serialVersionUID = 1L; + @Messages({"DataContentViewerOtherCasesTableModel.case=Case", "DataContentViewerOtherCasesTableModel.device=Device", "DataContentViewerOtherCasesTableModel.dataSource=Data Source", @@ -66,7 +68,7 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel { } }; - List nodeDataList; + private final List nodeDataList; DataContentViewerOtherCasesTableModel() { nodeDataList = new ArrayList<>(); @@ -118,7 +120,7 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel { /** * Map a column ID to the value in that cell for node message data. * - * @param nodeData The node message data. + * @param nodeData The node message data. * @param columnId The ID of the cell column. * * @return The value in the cell. @@ -133,7 +135,7 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel { /** * Map a column ID to the value in that cell for node instance data. * - * @param nodeData The node instance data. + * @param nodeData The node instance data. * @param columnId The ID of the cell column. * * @return The value in the cell. From cdce28d6dc852c9e50f0d40d3c977167d3d466ca Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 7 Aug 2018 17:38:51 -0400 Subject: [PATCH 104/105] 4014 auto format DataContentViewerOtherCases --- .../contentviewer/DataContentViewerOtherCases.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java index 9aa77e19a0..8a1ce6864e 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java @@ -960,7 +960,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi /** * Get the type of this UniquePathKey. - * + * * @return the type */ String getType() { @@ -969,7 +969,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi /** * Get the file path for the UniquePathKey. - * + * * @return the filePath */ String getFilePath() { @@ -978,7 +978,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi /** * Get the data source id for the UniquePathKey. - * + * * @return the dataSourceID */ String getDataSourceID() { From 3372c38afc5170ca3fb1a7e810a9e169642e1aab Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Wed, 8 Aug 2018 09:52:50 -0400 Subject: [PATCH 105/105] upated NEWS --- NEWS.txt | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/NEWS.txt b/NEWS.txt index cbdb02f349..3fcbff5b40 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -1,29 +1,25 @@ ---------------- VERSION 4.8.0 -------------- New Features: -- The case tree view can now be grouped by data source. -- Added a common files search tool that finds all instances of a file in a case. -- Text extraction optionally includes optical character recognition (OCR). -- Data source(s) filter added to ad hoc keyword search and file search by -attributes. -- SQLite tables can be now be exported to CSV files. -- User defined tags now appear first in tagging menus. -- Eliminated one tagging sub menu layer for faster tagging. -- Added Replace Tag item to tagging menus (shortcut for delete tag, add tag). -- The Other Occurrences content viewer now shows matches in the current case. -- A listing of cases in the central repository is displayed by the -central repository options panel. -- An interesting file artifact is now created when a "zip bomb" is detected. -- Text and queries sent to Solr are now normalized to handle diacritics, -ligatures, narrow and wide width Japanese characters, etc. -- An object detection ingest module that uses OpenCV and user-supplied -classifiers has been added to the "experimental" Net Beans Module (NBM). -- A data source processor that runs Volatility on a memory image has been -added to the "experimental" NBM. -- Comments can be added to all files (file correlation properties) recorded -in the central repository using a results view context menu item. -- Comments can be added to all correlation properties recorded -in the central repository using an Other Occurrences results content viewer -context menu item. +- Data Source Grouping: +-- The case tree view can now be grouped by data source. +-- Keyword and file search can now be restricted to a data source. +- Central Repository / Corrrelation: +-- New common files search feature that finds files that exist in multiple devices in the same case. +-- The Other Occurrences content viewer now shows matches in the current case (in addition to central repository). +-- Central repository options panel now shows cases that are in repo. +- A comment about a file can be created and saved in the central repository so that future cases and see it. +- Keyword Search: +-- Can enable OCR text extraction of PDF and JPG files using Tesseract. +-- Keyword search module normalizes Unicode text. +-- Keyword search module uses ICU to convert text files that do not have a BOM. +- Tagging: +-- Tagging menu changed to have user defined tags at top and "quick tag" removed one level of menus. +-- New "Replace Tag" feature to change the tag on an item. +- Other: +-- SQLite tables can be now be exported to CSV files. +-- An interesting file artifact is now created when a "zip bomb" is detected. +-- An object detection ingest module was added to the Experimental module. It requires an OpenCV trained model. + Bug Fixes: - Expanding the case tree is more efficient.