From 06b72eb558056e16abe9a96e08f93aca1b3081a0 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Wed, 13 Jun 2018 13:35:22 -0400 Subject: [PATCH 1/5] Use new class for other occurrence data --- .../DataContentViewerOtherCases.java | 150 ++++++++---------- ...DataContentViewerOtherCasesTableModel.java | 50 +++--- .../OtherOccurrenceNodeData.java | 104 ++++++++++++ 3 files changed, 194 insertions(+), 110 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java index 2a9fd30a49..ea886c1e93 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java @@ -466,31 +466,43 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi * * @return A collection of correlated artifact instances from other cases */ - 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 artifactInstances = new HashMap<>(); + HashMap nodeDataMap = new HashMap<>(); if (EamDb.isEnabled()) { - EamDb dbManager = EamDb.getInstance(); - artifactInstances.putAll(dbManager.getArtifactInstancesByTypeValue(corAttr.getCorrelationType(), corAttr.getCorrelationValue()).stream() - .filter(artifactInstance -> !artifactInstance.getCorrelationCase().getCaseUUID().equals(caseUUID) - || !artifactInstance.getCorrelationDataSource().getName().equals(dataSourceName) - || !artifactInstance.getCorrelationDataSource().getDeviceID().equals(deviceId)) - .collect(Collectors.toMap(correlationAttr -> new UniquePathKey(correlationAttr.getCorrelationDataSource().getDeviceID(), correlationAttr.getFilePath()), - correlationAttr -> correlationAttr))); - } + List instances = EamDb.getInstance().getArtifactInstancesByTypeValue(corAttr.getCorrelationType(), corAttr.getCorrelationValue()); - if (corAttr.getCorrelationType().getDisplayName().equals("Files")) { - List caseDbFiles = addCaseDbMatches(corAttr, openCase); - for (AbstractFile caseDbFile : caseDbFiles) { - addOrUpdateAttributeInstance(openCase, artifactInstances, caseDbFile); + 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 + // - the data source name is different + // - the data source device ID is different + // - (TODO) file path is different + if (!artifactInstance.getCorrelationCase().getCaseUUID().equals(caseUUID) + || !artifactInstance.getCorrelationDataSource().getName().equals(dataSourceName) + || !artifactInstance.getCorrelationDataSource().getDeviceID().equals(deviceId)) { + + OtherOccurrenceNodeData newNode = new OtherOccurrenceNodeData(artifactInstance, corAttr.getCorrelationType().getDisplayName(), corAttr.getCorrelationValue()); + UniquePathKey uniquePathKey = new UniquePathKey(newNode); + nodeDataMap.put(uniquePathKey, newNode); + } } } - return artifactInstances; + if (corAttr.getCorrelationType().getDisplayName().equals("Files")) { + List caseDbFiles = getCaseDbMatches(corAttr, openCase); + for (AbstractFile caseDbFile : caseDbFiles) { + addOrUpdateNodeData(openCase, nodeDataMap, caseDbFile); + } + } + + return nodeDataMap; } catch (EamDbException ex) { LOGGER.log(Level.SEVERE, "Error getting artifact instances from database.", ex); // NON-NLS } catch (NoCurrentCaseException ex) { @@ -504,7 +516,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi return new HashMap<>(0); } - private List addCaseDbMatches(CorrelationAttribute corAttr, Case openCase) throws NoCurrentCaseException, TskCoreException, EamDbException { + private List getCaseDbMatches(CorrelationAttribute corAttr, Case openCase) throws NoCurrentCaseException, TskCoreException, EamDbException { String md5 = corAttr.getCorrelationValue(); SleuthkitCase tsk = openCase.getSleuthkitCase(); @@ -522,58 +534,44 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi } /** - * Adds the file to the artifactInstances map if it does not already exist + * Adds the file to the nodeDataMap map if it does not already exist * * @param autopsyCase - * @param artifactInstances + * @param nodeDataMap * @param newFile * @throws TskCoreException * @throws EamDbException */ - private void addOrUpdateAttributeInstance(final Case autopsyCase, Map artifactInstances, AbstractFile newFile) throws TskCoreException, EamDbException { + private void addOrUpdateNodeData(final Case autopsyCase, Map nodeDataMap, AbstractFile newFile) throws TskCoreException, EamDbException { - // figure out if the casedb file is known via either hash or tags - TskData.FileKnown localKnown = newFile.getKnown(); - - if (localKnown != TskData.FileKnown.BAD) { + OtherOccurrenceNodeData newNode = new OtherOccurrenceNodeData(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) { List fileMatchTags = autopsyCase.getServices().getTagsManager().getContentTagsByContent(newFile); for (ContentTag tag : fileMatchTags) { TskData.FileKnown tagKnownStatus = tag.getName().getKnownStatus(); if (tagKnownStatus.equals(TskData.FileKnown.BAD)) { - localKnown = TskData.FileKnown.BAD; + newNode.updateKnown(TskData.FileKnown.BAD); break; } } } - // make a key to see if the file is already in the map - String filePath = newFile.getParentPath() + newFile.getName(); - String deviceId; - try { - deviceId = autopsyCase.getSleuthkitCase().getDataSource(newFile.getDataSource().getId()).getDeviceId(); - } catch (TskDataException | TskCoreException ex) { - LOGGER.log(Level.WARNING, "Error getting data source info: " + ex); - return; - } - UniquePathKey uniquePathKey = new UniquePathKey(deviceId, filePath); + // Make a key to see if the file is already in the map + UniquePathKey uniquePathKey = new UniquePathKey(newNode); - // double check that the CR version is BAD if the caseDB version is BAD. - if (artifactInstances.containsKey(uniquePathKey)) { - if (localKnown == TskData.FileKnown.BAD) { - CorrelationAttributeInstance prevInstance = artifactInstances.get(uniquePathKey); - prevInstance.setKnownStatus(localKnown); + // 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, add the new node to the map. + if (nodeDataMap.containsKey(uniquePathKey)) { + if (newNode.getKnown() == TskData.FileKnown.BAD) { + OtherOccurrenceNodeData prevInstance = nodeDataMap.get(uniquePathKey); + prevInstance.updateKnown(newNode.getKnown()); } - } - // add the data from the case DB by pushing data into CorrelationAttributeInstance class - else { - // NOTE: If we are in here, it is likely because CR is not enabled. So, we cannot rely - // on any of the methods that query the DB. - CorrelationCase correlationCase = new CorrelationCase(autopsyCase.getName(), autopsyCase.getDisplayName()); - - CorrelationDataSource correlationDataSource = CorrelationDataSource.fromTSKDataSource(correlationCase, newFile.getDataSource()); - - CorrelationAttributeInstance caseDbInstance = new CorrelationAttributeInstance(correlationCase, correlationDataSource, filePath, "", localKnown); - artifactInstances.put(uniquePathKey, caseDbInstance); + } else { + nodeDataMap.put(uniquePathKey, newNode); } } @@ -632,22 +630,13 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi // get the attributes we can correlate on correlationAttributes.addAll(getCorrelationAttributesFromNode(node)); for (CorrelationAttribute corAttr : correlationAttributes) { - Map corAttrInstances = new HashMap<>(0); + Map correlatedNodeDataMap = new HashMap<>(0); // get correlation and reference set instances from DB - corAttrInstances.putAll(getCorrelatedInstances(corAttr, dataSourceName, deviceId)); + correlatedNodeDataMap.putAll(getCorrelatedInstances(corAttr, dataSourceName, deviceId)); - corAttrInstances.values().forEach((corAttrInstance) -> { - try { - CorrelationAttribute newCeArtifact = new CorrelationAttribute( - corAttr.getCorrelationType(), - corAttr.getCorrelationValue() - ); - newCeArtifact.addInstance(corAttrInstance); - tableModel.addEamArtifact(newCeArtifact); - } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Error creating correlation attribute", ex); - } + correlatedNodeDataMap.values().forEach((nodeData) -> { + tableModel.addNodeData(nodeData); }); } @@ -816,33 +805,26 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi private final String dataSourceID; private final String filePath; + private final String type; - UniquePathKey(String theDataSource, String theFilePath) { + UniquePathKey(OtherOccurrenceNodeData nodeData) { super(); - dataSourceID = theDataSource; - filePath = theFilePath.toLowerCase(); - } - - /** - * - * @return the dataSourceID device ID - */ - String getDataSourceID() { - return dataSourceID; - } - - /** - * - * @return the filPath including the filename and extension. - */ - String getFilePath() { - return filePath; + dataSourceID = nodeData.getDeviceID(); + if (nodeData.getFilePath() != null) { + filePath = nodeData.getFilePath().toLowerCase(); + } else { + filePath = null; + } + type = nodeData.getType(); } @Override public boolean equals(Object other) { if (other instanceof UniquePathKey) { - return ((UniquePathKey) other).getDataSourceID().equals(dataSourceID) && ((UniquePathKey) other).getFilePath().equals(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; } @@ -852,7 +834,7 @@ 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); + return Objects.hash(dataSourceID, filePath, type); } } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java index f0ecb31e72..5febf88dc3 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java @@ -68,10 +68,10 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel { } }; - List eamArtifacts; + List nodeDataList; DataContentViewerOtherCasesTableModel() { - eamArtifacts = new ArrayList<>(); + nodeDataList = new ArrayList<>(); } @Override @@ -95,7 +95,7 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel { @Override public int getRowCount() { - return eamArtifacts.size(); + return nodeDataList.size(); } @Override @@ -105,15 +105,15 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel { @Override public Object getValueAt(int rowIdx, int colIdx) { - if (0 == eamArtifacts.size()) { + if (0 == nodeDataList.size()) { return Bundle.DataContentViewerOtherCasesTableModel_noData(); } return mapValueById(rowIdx, TableColumns.values()[colIdx]); } - public Object getRow(int rowIdx) { - return eamArtifacts.get(rowIdx); + Object getRow(int rowIdx) { + return nodeDataList.get(rowIdx); } /** @@ -125,40 +125,39 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel { * @return value in the cell */ private Object mapValueById(int rowIdx, TableColumns colId) { - CorrelationAttribute eamArtifact = eamArtifacts.get(rowIdx); - CorrelationAttributeInstance eamArtifactInstance = eamArtifact.getInstances().get(0); + OtherOccurrenceNodeData nodeData = nodeDataList.get(rowIdx); String value = Bundle.DataContentViewerOtherCasesTableModel_noData(); switch (colId) { case CASE_NAME: - if (null != eamArtifactInstance.getCorrelationCase()) { - value = eamArtifactInstance.getCorrelationCase().getDisplayName(); + if (null != nodeData.getCaseName()) { + value = nodeData.getCaseName(); } break; case DEVICE: - if (null != eamArtifactInstance.getCorrelationDataSource()) { - value = eamArtifactInstance.getCorrelationDataSource().getDeviceID(); + if (null != nodeData.getDeviceID()) { + value = nodeData.getDeviceID(); } break; case DATA_SOURCE: - if (null != eamArtifactInstance.getCorrelationDataSource()) { - value = eamArtifactInstance.getCorrelationDataSource().getName(); + if (null != nodeData.getDataSourceName()) { + value = nodeData.getDataSourceName(); } break; case FILE_PATH: - value = eamArtifactInstance.getFilePath(); + value = nodeData.getFilePath(); break; case TYPE: - value = eamArtifact.getCorrelationType().getDisplayName(); + value = nodeData.getType(); break; case VALUE: - value = eamArtifact.getCorrelationValue(); + value = nodeData.getValue(); break; case KNOWN: - value = eamArtifactInstance.getKnownStatus().getName(); + value = nodeData.getKnown().getName(); break; case COMMENT: - value = eamArtifactInstance.getComment(); + value = nodeData.getComment(); break; } return value; @@ -170,18 +169,17 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel { } /** - * Add one local central repository artifact to the table. + * Add one correlated instance object to the table * - * @param eamArtifact central repository artifact to add to the - * table + * @param newNodeData data to add to the table */ - public void addEamArtifact(CorrelationAttribute eamArtifact) { - eamArtifacts.add(eamArtifact); + void addNodeData(OtherOccurrenceNodeData newNodeData) { + nodeDataList.add(newNodeData); fireTableDataChanged(); } - public void clearTable() { - eamArtifacts.clear(); + 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 new file mode 100644 index 0000000000..c988ff30d9 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java @@ -0,0 +1,104 @@ +/* + * 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.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 OtherOccurrenceNodeData { + + private String caseName; + private String deviceID; + private String dataSourceName; + private final String filePath; + private final String type; + private final String value; + private TskData.FileKnown known; + private final String comment; + + OtherOccurrenceNodeData(CorrelationAttributeInstance instance, String type, String value) { + caseName = instance.getCorrelationCase().getDisplayName(); + deviceID = instance.getCorrelationDataSource().getDeviceID(); + dataSourceName = instance.getCorrelationDataSource().getName(); + filePath = instance.getFilePath(); + this.type = type; + this.value = value; + known = instance.getKnownStatus(); + comment = instance.getComment(); + } + + 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()); + } + + filePath = newFile.getParentPath() + newFile.getName(); + type = "Files"; + value = newFile.getMd5Hash(); + known = newFile.getKnown(); + comment = ""; + } + + void updateKnown(TskData.FileKnown newKnownStatus) { + known = newKnownStatus; + } + + String getCaseName() { + return caseName; + } + + String getDeviceID() { + return deviceID; + } + + String getDataSourceName() { + return dataSourceName; + } + + String getFilePath() { + return filePath; + } + + String getType() { + return type; + } + + String getValue() { + return value; + } + + TskData.FileKnown getKnown() { + return known; + } + + String getComment() { + return comment; + } +} From 2a8fa66bbf51d8c2e1593cc69515dadf5b1a7dc0 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Fri, 15 Jun 2018 09:21:45 -0400 Subject: [PATCH 2/5] Disable the CR-based context menu items if CR is not enabled. With CR disabled, don't enabled the other occurrences tab if the file has no MD5. Added comments. --- .../DataContentViewerOtherCases.java | 36 ++++---- .../OtherOccurrenceNodeData.java | 90 +++++++++++++++++-- 2 files changed, 104 insertions(+), 22 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java index e9ab49cbf6..298a8763fc 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java @@ -56,7 +56,6 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase; -import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -69,7 +68,6 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskData; -import org.sleuthkit.datamodel.TskDataException; /** * View correlation results from other cases @@ -458,9 +456,10 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi } /** - * Query the database for artifact instances from other cases correlated to - * the given central repository artifact. Instances from the same datasource - * / device will also be included. + * 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 @@ -521,6 +520,15 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi return new HashMap<>(0); } + /** + * 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 + */ private List getCaseDbMatches(CorrelationAttribute corAttr, Case openCase) throws NoCurrentCaseException, TskCoreException, EamDbException { String md5 = corAttr.getCorrelationValue(); @@ -570,7 +578,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi // 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, add the new node to the map. + // 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); @@ -583,18 +591,20 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi @Override public boolean isSupported(Node node) { - this.file = this.getAbstractFileFromNode(node); - // Is supported if this node - // has correlatable content (File, BlackboardArtifact) OR - // other common files across datasources. + // Is supported if one of the following is true: + // - The central repo is enabled and the node has correlatable content + // (either through the MD5 hash of the associated file or through a BlackboardArtifact) + // - The central repo is disabled and the backing file has a valid MD5 hash + this.file = this.getAbstractFileFromNode(node); if (EamDb.isEnabled()) { return this.file != null && this.file.getSize() > 0 && !getCorrelationAttributesFromNode(node).isEmpty(); } else { return this.file != null - && this.file.getSize() > 0; + && this.file.getSize() > 0 + && ((this.file.getMd5Hash() != null) && ( ! this.file.getMd5Hash().isEmpty())); } } @@ -813,16 +823,12 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi private void rightClickPopupMenuPopupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent evt) {//GEN-FIRST:event_rightClickPopupMenuPopupMenuWillBecomeVisible boolean enableCentralRepoActions = false; - boolean enableComment = false; if (EamDbUtil.useCentralRepo() && otherCasesTable.getSelectedRowCount() == 1) { int rowIndex = otherCasesTable.getSelectedRow(); OtherOccurrenceNodeData selectedNode = (OtherOccurrenceNodeData) tableModel.getRow(rowIndex); if (selectedNode.isCentralRepoNode()) { enableCentralRepoActions = true; - if (selectedNode.isFileType()) { - enableComment = true; - } } } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java index 57534eb15e..3a13955974 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java @@ -28,9 +28,14 @@ import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskDataException; +/** + * Class for populating the Other Occurrences tab + */ class OtherOccurrenceNodeData { - private final String FILE_TYPE = "Files"; + // For now hard code the string for the central repo files type, since + // getting it dynamically can fail. + private final String FILE_TYPE_STR = "Files"; private String caseName; private String deviceID; @@ -45,6 +50,12 @@ class OtherOccurrenceNodeData { 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(); @@ -59,6 +70,12 @@ class OtherOccurrenceNodeData { 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 { @@ -70,8 +87,8 @@ class OtherOccurrenceNodeData { } filePath = newFile.getParentPath() + newFile.getName(); - typeStr = FILE_TYPE; - this.type = null; // TEMP + typeStr = FILE_TYPE_STR; + this.type = null; // We can't make the Type object without the central repo enabled value = newFile.getMd5Hash(); known = newFile.getKnown(); comment = ""; @@ -79,21 +96,34 @@ class OtherOccurrenceNodeData { originalAbstractFile = newFile; } + /** + * Check if this node is a "file" type + * @return true if it is a file type + */ boolean isFileType() { - return FILE_TYPE.equals(typeStr); + 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; } + /** + * 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 - * @return + * 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() ) { @@ -104,42 +134,88 @@ class OtherOccurrenceNodeData { 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; } - AbstractFile getAbstractFile() { + /** + * 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"); From 5eccf7b4deb2f7724b15973aa706aae38460ade7 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Fri, 15 Jun 2018 10:12:33 -0400 Subject: [PATCH 3/5] Update the comment in the UI --- .../AddEditCentralRepoCommentAction.java | 8 +++++++- .../centralrepository/CentralRepoCommentDialog.java | 11 ++++++++++- .../contentviewer/DataContentViewerOtherCases.java | 5 ++++- .../contentviewer/OtherOccurrenceNodeData.java | 12 ++++++++++-- 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java b/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java index 8c03883523..e3f2899278 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java @@ -83,8 +83,12 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction { * 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 new comment is returned in case it is needed to update the display + * + * @return the newly added comment or null if it was not updated */ - public void addEditCentralRepoComment() { + public String addEditCentralRepoComment() { CentralRepoCommentDialog centralRepoCommentDialog = new CentralRepoCommentDialog(correlationAttribute, title); centralRepoCommentDialog.display(); @@ -102,7 +106,9 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction { } catch (EamDbException ex) { logger.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); } + return centralRepoCommentDialog.getComment(); } + return null; } /** diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.java b/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.java index 4e42bfe9d7..35e005daed 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.java @@ -31,6 +31,7 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog { private final CorrelationAttribute correlationAttribute; private boolean commentUpdated = false; + private String comment = ""; /** * Create an instance. @@ -71,6 +72,14 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog { boolean isCommentUpdated() { return commentUpdated; } + + /** + * Get the newly added comment + * @return the comment + */ + String getComment() { + return comment; + } /** * This method is called from within the constructor to initialize the form. @@ -168,7 +177,7 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog { }//GEN-LAST:event_cancelButtonActionPerformed private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed - String comment = commentTextArea.getText(); + comment = commentTextArea.getText(); correlationAttribute.getInstances().get(0).setComment(comment); commentUpdated = true; diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java index 298a8763fc..de0c6467c8 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java @@ -120,7 +120,10 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi try { OtherOccurrenceNodeData selectedNode = (OtherOccurrenceNodeData) tableModel.getRow(otherCasesTable.getSelectedRow()); AddEditCentralRepoCommentAction action = AddEditCentralRepoCommentAction.createAddEditCommentAction(selectedNode.createCorrelationAttribute()); - action.addEditCentralRepoComment(); + String newComment = action.addEditCentralRepoComment(); + if (newComment != null) { + selectedNode.updateComment(newComment); + } otherCasesTable.repaint(); } catch (EamDbException ex) { logger.log(Level.SEVERE, "Error performing Add/Edit Comment action", ex); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java index 3a13955974..03d33b3140 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java @@ -45,7 +45,7 @@ class OtherOccurrenceNodeData { private final CorrelationAttribute.Type type; private final String value; private TskData.FileKnown known; - private final String comment; + private String comment; private AbstractFile originalAbstractFile = null; private CorrelationAttributeInstance originalCorrelationInstance = null; @@ -88,7 +88,7 @@ class OtherOccurrenceNodeData { filePath = newFile.getParentPath() + newFile.getName(); typeStr = FILE_TYPE_STR; - this.type = null; // We can't make the Type object without the central repo enabled + this.type = null; value = newFile.getMd5Hash(); known = newFile.getKnown(); comment = ""; @@ -112,6 +112,14 @@ class OtherOccurrenceNodeData { 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 From 0766f645a6aeac9cacd221ed1d848bf9e24d8743 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Fri, 15 Jun 2018 10:59:56 -0400 Subject: [PATCH 4/5] Codacy --- .../contentviewer/OtherOccurrenceNodeData.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java index 03d33b3140..958068fb14 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java @@ -35,9 +35,9 @@ class OtherOccurrenceNodeData { // For now hard code the string for the central repo files type, since // getting it dynamically can fail. - private final String FILE_TYPE_STR = "Files"; + private static final String FILE_TYPE_STR = "Files"; - private String caseName; + private final String caseName; private String deviceID; private String dataSourceName; private final String filePath; @@ -83,7 +83,7 @@ class OtherOccurrenceNodeData { deviceID = dataSource.getDeviceId(); dataSourceName = dataSource.getName(); } catch (TskDataException | TskCoreException ex) { - throw new EamDbException("Error loading data source for abstract file ID " + newFile.getId()); + throw new EamDbException("Error loading data source for abstract file ID " + newFile.getId(), ex); } filePath = newFile.getParentPath() + newFile.getName(); From 1cf2028d877bb0ec4c19754b82a029049c3b94e0 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Fri, 15 Jun 2018 11:25:33 -0400 Subject: [PATCH 5/5] Save the current comment to prevent having to return null if the user cancels. Fix a few deprecated function calls. --- .../AddEditCentralRepoCommentAction.java | 8 ++++---- .../CentralRepoCommentDialog.java | 17 ++++++++++++----- .../DataContentViewerOtherCases.java | 6 ++---- .../datamodel/AbstractSqlEamDb.java | 2 +- .../datamodel/PostgresEamDbSettings.java | 2 +- 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java b/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java index e3f2899278..dfeb4fbdcd 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java @@ -84,9 +84,10 @@ 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 new comment is returned in case it is needed to update the display + * The current comment for this instance is returned in case it is needed to + * update the display. * - * @return the newly added comment or null if it was not updated + * @return the current comment for this instance */ public String addEditCentralRepoComment() { CentralRepoCommentDialog centralRepoCommentDialog = new CentralRepoCommentDialog(correlationAttribute, title); @@ -106,9 +107,8 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction { } catch (EamDbException ex) { logger.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); } - return centralRepoCommentDialog.getComment(); } - return null; + return centralRepoCommentDialog.getComment(); } /** diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.java b/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.java index 35e005daed..c95b0bfde7 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.java @@ -31,7 +31,7 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog { private final CorrelationAttribute correlationAttribute; private boolean commentUpdated = false; - private String comment = ""; + private String currentComment = ""; /** * Create an instance. @@ -45,6 +45,11 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog { initComponents(); CorrelationAttributeInstance instance = correlationAttribute.getInstances().get(0); + + // Store the original comment + if (instance.getComment() != null) { + currentComment = instance.getComment(); + } pathLabel.setText(instance.getFilePath()); commentTextArea.setText(instance.getComment()); @@ -74,11 +79,13 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog { } /** - * Get the newly added comment + * 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() { - return comment; + return currentComment; } /** @@ -177,8 +184,8 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog { }//GEN-LAST:event_cancelButtonActionPerformed private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed - comment = commentTextArea.getText(); - correlationAttribute.getInstances().get(0).setComment(comment); + currentComment = commentTextArea.getText(); + correlationAttribute.getInstances().get(0).setComment(currentComment); commentUpdated = true; dispose(); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java index de0c6467c8..15ed21d753 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java @@ -120,10 +120,8 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi try { OtherOccurrenceNodeData selectedNode = (OtherOccurrenceNodeData) tableModel.getRow(otherCasesTable.getSelectedRow()); AddEditCentralRepoCommentAction action = AddEditCentralRepoCommentAction.createAddEditCommentAction(selectedNode.createCorrelationAttribute()); - String newComment = action.addEditCentralRepoComment(); - if (newComment != null) { - selectedNode.updateComment(newComment); - } + String currentComment = action.addEditCentralRepoComment(); + selectedNode.updateComment(currentComment); otherCasesTable.repaint(); } catch (EamDbException ex) { logger.log(Level.SEVERE, "Error performing Add/Edit Comment action", ex); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java index 45bc197283..59df6b7bbc 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java @@ -1772,7 +1772,7 @@ abstract class AbstractSqlEamDb implements EamDb { } catch (SQLException ex) { throw new EamDbException("Error getting all artifact instances from instances table", ex); } finally { - EamDbUtil.closePreparedStatement(preparedStatement); + EamDbUtil.closeStatement(preparedStatement); EamDbUtil.closeResultSet(resultSet); EamDbUtil.closeConnection(conn); } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java index 1154da273d..32de4e7646 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java @@ -221,7 +221,7 @@ public final class PostgresEamDbSettings { LOGGER.log(Level.SEVERE, "Failed to execute database existance query.", ex); // NON-NLS return false; } finally { - EamDbUtil.closePreparedStatement(ps); + EamDbUtil.closeStatement(ps); EamDbUtil.closeResultSet(rs); EamDbUtil.closeConnection(conn); }