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/101] 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/101] 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/101] 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/101] 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/101] 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/101] 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/101] 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/101] 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/101] 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/101] 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/101] 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/101] 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/101] 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 60446f04066a0138d8f5f534e75256c19af33c13 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 18 Jul 2018 13:47:07 -0400 Subject: [PATCH 014/101] 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 e5a8ae21f557ec6900d2cf4279b0ef21e7e40936 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 18 Jul 2018 16:54:36 -0400 Subject: [PATCH 015/101] 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 016/101] 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 017/101] 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 018/101] 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 019/101] 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 020/101] 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 021/101] 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 022/101] 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 023/101] 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 024/101] 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 025/101] 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 026/101] 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 027/101] 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 028/101] 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 029/101] 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 030/101] 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 031/101] 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 032/101] 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 033/101] 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 034/101] 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 035/101] 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 036/101] 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 037/101] 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 038/101] 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 039/101] 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 040/101] 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 041/101] 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 042/101] 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 043/101] 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 044/101] 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 045/101] 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 046/101] 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 047/101] 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 048/101] 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 049/101] 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 050/101] 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 051/101] 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 052/101] 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 053/101] 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 054/101] 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 055/101] 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 056/101] 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 057/101] 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 058/101] 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 059/101] 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 060/101] 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 061/101] 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 062/101] 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 063/101] 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 064/101] 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 065/101] 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 066/101] 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 067/101] 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 068/101] 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 069/101] 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 070/101] 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 071/101] 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 072/101] 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 073/101] 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 074/101] 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 075/101] 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 076/101] 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 077/101] 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 078/101] 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 079/101] 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 080/101] 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 081/101] 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 082/101] 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 083/101] 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 084/101] 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 085/101] 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 086/101] 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 087/101] 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 088/101] 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 089/101] 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 090/101] 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 091/101] 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 092/101] 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 093/101] 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 094/101] 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 095/101] 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 096/101] 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 097/101] 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 098/101] 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 099/101] 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 100/101] 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 101/101] 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.