Merge pull request #3861 from APriestman/3888_refactorOtherOccurrences

3888 Refactor other occurrences table
This commit is contained in:
Richard Cordovano 2018-06-18 14:50:46 -04:00 committed by GitHub
commit f6d533a966
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 396 additions and 142 deletions

View File

@ -83,8 +83,13 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction {
* comment. The comment will be updated in the database if the 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 * exists there, or a new file instance will be added to the database with
* the comment attached otherwise. * 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
*/ */
public void addEditCentralRepoComment() { public String addEditCentralRepoComment() {
CentralRepoCommentDialog centralRepoCommentDialog = new CentralRepoCommentDialog(correlationAttribute, title); CentralRepoCommentDialog centralRepoCommentDialog = new CentralRepoCommentDialog(correlationAttribute, title);
centralRepoCommentDialog.display(); centralRepoCommentDialog.display();
@ -103,6 +108,7 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction {
logger.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); logger.log(Level.SEVERE, "Error connecting to Central Repository database.", ex);
} }
} }
return centralRepoCommentDialog.getComment();
} }
/** /**

View File

@ -31,6 +31,7 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog {
private final CorrelationAttribute correlationAttribute; private final CorrelationAttribute correlationAttribute;
private boolean commentUpdated = false; private boolean commentUpdated = false;
private String currentComment = "";
/** /**
* Create an instance. * Create an instance.
@ -45,6 +46,11 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog {
CorrelationAttributeInstance instance = correlationAttribute.getInstances().get(0); CorrelationAttributeInstance instance = correlationAttribute.getInstances().get(0);
// Store the original comment
if (instance.getComment() != null) {
currentComment = instance.getComment();
}
pathLabel.setText(instance.getFilePath()); pathLabel.setText(instance.getFilePath());
commentTextArea.setText(instance.getComment()); commentTextArea.setText(instance.getComment());
@ -72,6 +78,16 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog {
return commentUpdated; return commentUpdated;
} }
/**
* 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 currentComment;
}
/** /**
* This method is called from within the constructor to initialize the form. * 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 * WARNING: Do NOT modify this code. The content of this method is always
@ -168,8 +184,8 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog {
}//GEN-LAST:event_cancelButtonActionPerformed }//GEN-LAST:event_cancelButtonActionPerformed
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
String comment = commentTextArea.getText(); currentComment = commentTextArea.getText();
correlationAttribute.getInstances().get(0).setComment(comment); correlationAttribute.getInstances().get(0).setComment(currentComment);
commentUpdated = true; commentUpdated = true;
dispose(); dispose();

View File

@ -56,7 +56,6 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil; import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact; 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.autopsy.centralrepository.datamodel.EamDbUtil;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskDataException;
/** /**
* View correlation results from other cases * View correlation results from other cases
@ -119,10 +117,15 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
} else if (jmi.equals(showCommonalityMenuItem)) { } else if (jmi.equals(showCommonalityMenuItem)) {
showCommonalityDetails(); showCommonalityDetails();
} else if (jmi.equals(addCommentMenuItem)) { } else if (jmi.equals(addCommentMenuItem)) {
CorrelationAttribute selectedAttribute = (CorrelationAttribute) tableModel.getRow(otherCasesTable.getSelectedRow()); try {
AddEditCentralRepoCommentAction action = AddEditCentralRepoCommentAction.createAddEditCommentAction(selectedAttribute); OtherOccurrenceNodeData selectedNode = (OtherOccurrenceNodeData) tableModel.getRow(otherCasesTable.getSelectedRow());
action.addEditCentralRepoComment(); AddEditCentralRepoCommentAction action = AddEditCentralRepoCommentAction.createAddEditCommentAction(selectedNode.createCorrelationAttribute());
String currentComment = action.addEditCentralRepoComment();
selectedNode.updateComment(currentComment);
otherCasesTable.repaint(); otherCasesTable.repaint();
} catch (EamDbException ex) {
logger.log(Level.SEVERE, "Error performing Add/Edit Comment action", ex);
}
} }
} }
}; };
@ -202,8 +205,8 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
if (-1 != selectedRowViewIdx) { if (-1 != selectedRowViewIdx) {
EamDb dbManager = EamDb.getInstance(); EamDb dbManager = EamDb.getInstance();
int selectedRowModelIdx = otherCasesTable.convertRowIndexToModel(selectedRowViewIdx); int selectedRowModelIdx = otherCasesTable.convertRowIndexToModel(selectedRowViewIdx);
CorrelationAttribute eamArtifact = (CorrelationAttribute) tableModel.getRow(selectedRowModelIdx); OtherOccurrenceNodeData nodeData = (OtherOccurrenceNodeData) tableModel.getRow(selectedRowModelIdx);
CorrelationCase eamCasePartial = eamArtifact.getInstances().get(0).getCorrelationCase(); CorrelationCase eamCasePartial = nodeData.getCorrelationAttributeInstance().getCorrelationCase();
if (eamCasePartial == null) { if (eamCasePartial == null) {
JOptionPane.showConfirmDialog(showCaseDetailsMenuItem, JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetailsReference(), Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetailsReference(),
@ -454,9 +457,10 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
} }
/** /**
* Query the database for artifact instances from other cases correlated to * Query the central repo database (if enabled) and the case database to find all
* the given central repository artifact. Instances from the same datasource * artifact instances correlated to the given central repository artifact. If the
* / device will also be included. * 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 corAttr CorrelationAttribute to query for
* @param dataSourceName Data source to filter results * @param dataSourceName Data source to filter results
@ -464,33 +468,46 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
* *
* @return A collection of correlated artifact instances * @return A collection of correlated artifact instances
*/ */
private Map<UniquePathKey, CorrelationAttributeInstance> getCorrelatedInstances(CorrelationAttribute corAttr, String dataSourceName, String deviceId) { private Map<UniquePathKey,OtherOccurrenceNodeData> getCorrelatedInstances(CorrelationAttribute corAttr, String dataSourceName, String deviceId) {
// @@@ Check exception // @@@ Check exception
try { try {
final Case openCase = Case.getCurrentCase(); final Case openCase = Case.getCurrentCase();
String caseUUID = openCase.getName(); String caseUUID = openCase.getName();
String filePath = (file.getParentPath() + file.getName()).toLowerCase();
HashMap<UniquePathKey, CorrelationAttributeInstance> artifactInstances = new HashMap<>(); HashMap<UniquePathKey,OtherOccurrenceNodeData> nodeDataMap = new HashMap<>();
if (EamDb.isEnabled()) { if (EamDb.isEnabled()) {
EamDb dbManager = EamDb.getInstance(); List<CorrelationAttributeInstance> instances = EamDb.getInstance().getArtifactInstancesByTypeValue(corAttr.getCorrelationType(), corAttr.getCorrelationValue());
artifactInstances.putAll(dbManager.getArtifactInstancesByTypeValue(corAttr.getCorrelationType(), corAttr.getCorrelationValue()).stream()
.filter(artifactInstance -> !artifactInstance.getFilePath().equals(filePath) for (CorrelationAttributeInstance artifactInstance:instances) {
|| !artifactInstance.getCorrelationCase().getCaseUUID().equals(caseUUID)
// 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
// - the file path is different
if (!artifactInstance.getCorrelationCase().getCaseUUID().equals(caseUUID)
|| !artifactInstance.getCorrelationDataSource().getName().equals(dataSourceName) || !artifactInstance.getCorrelationDataSource().getName().equals(dataSourceName)
|| !artifactInstance.getCorrelationDataSource().getDeviceID().equals(deviceId)) || !artifactInstance.getCorrelationDataSource().getDeviceID().equals(deviceId)
.collect(Collectors.toMap(correlationAttr -> new UniquePathKey(correlationAttr.getCorrelationDataSource().getDeviceID(), correlationAttr.getFilePath()), || !artifactInstance.getFilePath().equalsIgnoreCase(file.getParentPath() + file.getName())) {
correlationAttr -> correlationAttr)));
OtherOccurrenceNodeData newNode = new OtherOccurrenceNodeData(artifactInstance, corAttr.getCorrelationType(), corAttr.getCorrelationValue());
UniquePathKey uniquePathKey = new UniquePathKey(newNode);
nodeDataMap.put(uniquePathKey, newNode);
}
}
} }
if (corAttr.getCorrelationType().getDisplayName().equals("Files")) { if (corAttr.getCorrelationType().getDisplayName().equals("Files")) {
List<AbstractFile> caseDbFiles = addCaseDbMatches(corAttr, openCase); List<AbstractFile> caseDbFiles = getCaseDbMatches(corAttr, openCase);
for (AbstractFile caseDbFile : caseDbFiles) { for (AbstractFile caseDbFile : caseDbFiles) {
addOrUpdateAttributeInstance(openCase, artifactInstances, caseDbFile); addOrUpdateNodeData(openCase, nodeDataMap, caseDbFile);
} }
} }
return artifactInstances; return nodeDataMap;
} catch (EamDbException ex) { } catch (EamDbException ex) {
logger.log(Level.SEVERE, "Error getting artifact instances from database.", ex); // NON-NLS logger.log(Level.SEVERE, "Error getting artifact instances from database.", ex); // NON-NLS
} catch (NoCurrentCaseException ex) { } catch (NoCurrentCaseException ex) {
@ -504,7 +521,16 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
return new HashMap<>(0); return new HashMap<>(0);
} }
private List<AbstractFile> addCaseDbMatches(CorrelationAttribute corAttr, Case openCase) throws NoCurrentCaseException, TskCoreException, EamDbException { /**
* 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<AbstractFile> getCaseDbMatches(CorrelationAttribute corAttr, Case openCase) throws NoCurrentCaseException, TskCoreException, EamDbException {
String md5 = corAttr.getCorrelationValue(); String md5 = corAttr.getCorrelationValue();
SleuthkitCase tsk = openCase.getSleuthkitCase(); SleuthkitCase tsk = openCase.getSleuthkitCase();
@ -522,75 +548,64 @@ 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 autopsyCase
* @param artifactInstances * @param nodeDataMap
* @param newFile * @param newFile
* *
* @throws TskCoreException * @throws TskCoreException
* @throws EamDbException * @throws EamDbException
*/ */
private void addOrUpdateAttributeInstance(final Case autopsyCase, Map<UniquePathKey, CorrelationAttributeInstance> artifactInstances, AbstractFile newFile) throws TskCoreException, EamDbException { private void addOrUpdateNodeData(final Case autopsyCase, Map<UniquePathKey,OtherOccurrenceNodeData> nodeDataMap, AbstractFile newFile) throws TskCoreException, EamDbException {
// figure out if the casedb file is known via either hash or tags OtherOccurrenceNodeData newNode = new OtherOccurrenceNodeData(newFile, autopsyCase);
TskData.FileKnown localKnown = newFile.getKnown();
if (localKnown != TskData.FileKnown.BAD) { // If the caseDB object has a notable tag associated with it, update
// the known status to BAD
if (newNode.getKnown() != TskData.FileKnown.BAD) {
List<ContentTag> fileMatchTags = autopsyCase.getServices().getTagsManager().getContentTagsByContent(newFile); List<ContentTag> fileMatchTags = autopsyCase.getServices().getTagsManager().getContentTagsByContent(newFile);
for (ContentTag tag : fileMatchTags) { for (ContentTag tag : fileMatchTags) {
TskData.FileKnown tagKnownStatus = tag.getName().getKnownStatus(); TskData.FileKnown tagKnownStatus = tag.getName().getKnownStatus();
if (tagKnownStatus.equals(TskData.FileKnown.BAD)) { if (tagKnownStatus.equals(TskData.FileKnown.BAD)) {
localKnown = TskData.FileKnown.BAD; newNode.updateKnown(TskData.FileKnown.BAD);
break; break;
} }
} }
} }
// make a key to see if the file is already in the map // Make a key to see if the file is already in the map
String filePath = newFile.getParentPath() + newFile.getName(); UniquePathKey uniquePathKey = new UniquePathKey(newNode);
String deviceId;
try { // If this node is already in the list, the only thing we need to do is
deviceId = autopsyCase.getSleuthkitCase().getDataSource(newFile.getDataSource().getId()).getDeviceId(); // update the known status to BAD if the caseDB version had known status BAD.
} catch (TskDataException | TskCoreException ex) { // Otherwise this is a new node so add the new node to the map.
logger.log(Level.WARNING, "Error getting data source info: {0}", ex); if (nodeDataMap.containsKey(uniquePathKey)) {
return; if (newNode.getKnown() == TskData.FileKnown.BAD) {
OtherOccurrenceNodeData prevInstance = nodeDataMap.get(uniquePathKey);
prevInstance.updateKnown(newNode.getKnown());
} }
UniquePathKey uniquePathKey = new UniquePathKey(deviceId, filePath); } else {
nodeDataMap.put(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);
}
} // 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);
} }
} }
@Override @Override
public boolean isSupported(Node node) { 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()) { if (EamDb.isEnabled()) {
return this.file != null return this.file != null
&& this.file.getSize() > 0 && this.file.getSize() > 0
&& !getCorrelationAttributesFromNode(node).isEmpty(); && !getCorrelationAttributesFromNode(node).isEmpty();
} else { } else {
return this.file != null return this.file != null
&& this.file.getSize() > 0; && this.file.getSize() > 0
&& ((this.file.getMd5Hash() != null) && ( ! this.file.getMd5Hash().isEmpty()));
} }
} }
@ -632,22 +647,14 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
// get the attributes we can correlate on // get the attributes we can correlate on
correlationAttributes.addAll(getCorrelationAttributesFromNode(node)); correlationAttributes.addAll(getCorrelationAttributesFromNode(node));
for (CorrelationAttribute corAttr : correlationAttributes) { for (CorrelationAttribute corAttr : correlationAttributes) {
Map<UniquePathKey, CorrelationAttributeInstance> corAttrInstances = new HashMap<>(0); Map<UniquePathKey,OtherOccurrenceNodeData> correlatedNodeDataMap = new HashMap<>(0);
// get correlation and reference set instances from DB // get correlation and reference set instances from DB
corAttrInstances.putAll(getCorrelatedInstances(corAttr, dataSourceName, deviceId)); correlatedNodeDataMap.putAll(getCorrelatedInstances(corAttr, dataSourceName, deviceId));
correlatedNodeDataMap.values().forEach((nodeData) -> {
tableModel.addNodeData(nodeData);
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);
}
}); });
} }
@ -816,18 +823,19 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents
private void rightClickPopupMenuPopupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent evt) {//GEN-FIRST:event_rightClickPopupMenuPopupMenuWillBecomeVisible private void rightClickPopupMenuPopupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent evt) {//GEN-FIRST:event_rightClickPopupMenuPopupMenuWillBecomeVisible
boolean addCommentMenuItemVisible = false; boolean enableCentralRepoActions = false;
if (EamDbUtil.useCentralRepo() && otherCasesTable.getSelectedRowCount() == 1) { if (EamDbUtil.useCentralRepo() && otherCasesTable.getSelectedRowCount() == 1) {
int rowIndex = otherCasesTable.getSelectedRow(); int rowIndex = otherCasesTable.getSelectedRow();
CorrelationAttribute selectedAttribute = (CorrelationAttribute) tableModel.getRow(rowIndex); OtherOccurrenceNodeData selectedNode = (OtherOccurrenceNodeData) tableModel.getRow(rowIndex);
if (selectedAttribute.getInstances().get(0).isDatabaseInstance() if (selectedNode.isCentralRepoNode()) {
&& selectedAttribute.getCorrelationType().getId() == CorrelationAttribute.FILES_TYPE_ID) { enableCentralRepoActions = true;
addCommentMenuItemVisible = true;
} }
} }
addCommentMenuItem.setVisible(addCommentMenuItemVisible); addCommentMenuItem.setVisible(enableCentralRepoActions);
showCaseDetailsMenuItem.setVisible(enableCentralRepoActions);
showCommonalityMenuItem.setVisible(enableCentralRepoActions);
}//GEN-LAST:event_rightClickPopupMenuPopupMenuWillBecomeVisible }//GEN-LAST:event_rightClickPopupMenuPopupMenuWillBecomeVisible
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
@ -854,33 +862,26 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
private final String dataSourceID; private final String dataSourceID;
private final String filePath; private final String filePath;
private final String type;
UniquePathKey(String theDataSource, String theFilePath) { UniquePathKey(OtherOccurrenceNodeData nodeData) {
super(); super();
dataSourceID = theDataSource; dataSourceID = nodeData.getDeviceID();
filePath = theFilePath.toLowerCase(); if (nodeData.getFilePath() != null) {
filePath = nodeData.getFilePath().toLowerCase();
} else {
filePath = null;
} }
type = nodeData.getType();
/**
*
* @return the dataSourceID device ID
*/
String getDataSourceID() {
return dataSourceID;
}
/**
*
* @return the filPath including the filename and extension.
*/
String getFilePath() {
return filePath;
} }
@Override @Override
public boolean equals(Object other) { public boolean equals(Object other) {
if (other instanceof UniquePathKey) { 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; return false;
} }
@ -890,7 +891,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
//int hash = 7; //int hash = 7;
//hash = 67 * hash + this.dataSourceID.hashCode(); //hash = 67 * hash + this.dataSourceID.hashCode();
//hash = 67 * hash + this.filePath.hashCode(); //hash = 67 * hash + this.filePath.hashCode();
return Objects.hash(dataSourceID, filePath); return Objects.hash(dataSourceID, filePath, type);
} }
} }

View File

@ -68,10 +68,10 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel {
} }
}; };
List<CorrelationAttribute> eamArtifacts; List<OtherOccurrenceNodeData> nodeDataList;
DataContentViewerOtherCasesTableModel() { DataContentViewerOtherCasesTableModel() {
eamArtifacts = new ArrayList<>(); nodeDataList = new ArrayList<>();
} }
@Override @Override
@ -95,7 +95,7 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel {
@Override @Override
public int getRowCount() { public int getRowCount() {
return eamArtifacts.size(); return nodeDataList.size();
} }
@Override @Override
@ -105,15 +105,15 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel {
@Override @Override
public Object getValueAt(int rowIdx, int colIdx) { public Object getValueAt(int rowIdx, int colIdx) {
if (0 == eamArtifacts.size()) { if (0 == nodeDataList.size()) {
return Bundle.DataContentViewerOtherCasesTableModel_noData(); return Bundle.DataContentViewerOtherCasesTableModel_noData();
} }
return mapValueById(rowIdx, TableColumns.values()[colIdx]); return mapValueById(rowIdx, TableColumns.values()[colIdx]);
} }
public Object getRow(int rowIdx) { Object getRow(int rowIdx) {
return eamArtifacts.get(rowIdx); return nodeDataList.get(rowIdx);
} }
/** /**
@ -125,40 +125,39 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel {
* @return value in the cell * @return value in the cell
*/ */
private Object mapValueById(int rowIdx, TableColumns colId) { private Object mapValueById(int rowIdx, TableColumns colId) {
CorrelationAttribute eamArtifact = eamArtifacts.get(rowIdx); OtherOccurrenceNodeData nodeData = nodeDataList.get(rowIdx);
CorrelationAttributeInstance eamArtifactInstance = eamArtifact.getInstances().get(0);
String value = Bundle.DataContentViewerOtherCasesTableModel_noData(); String value = Bundle.DataContentViewerOtherCasesTableModel_noData();
switch (colId) { switch (colId) {
case CASE_NAME: case CASE_NAME:
if (null != eamArtifactInstance.getCorrelationCase()) { if (null != nodeData.getCaseName()) {
value = eamArtifactInstance.getCorrelationCase().getDisplayName(); value = nodeData.getCaseName();
} }
break; break;
case DEVICE: case DEVICE:
if (null != eamArtifactInstance.getCorrelationDataSource()) { if (null != nodeData.getDeviceID()) {
value = eamArtifactInstance.getCorrelationDataSource().getDeviceID(); value = nodeData.getDeviceID();
} }
break; break;
case DATA_SOURCE: case DATA_SOURCE:
if (null != eamArtifactInstance.getCorrelationDataSource()) { if (null != nodeData.getDataSourceName()) {
value = eamArtifactInstance.getCorrelationDataSource().getName(); value = nodeData.getDataSourceName();
} }
break; break;
case FILE_PATH: case FILE_PATH:
value = eamArtifactInstance.getFilePath(); value = nodeData.getFilePath();
break; break;
case TYPE: case TYPE:
value = eamArtifact.getCorrelationType().getDisplayName(); value = nodeData.getType();
break; break;
case VALUE: case VALUE:
value = eamArtifact.getCorrelationValue(); value = nodeData.getValue();
break; break;
case KNOWN: case KNOWN:
value = eamArtifactInstance.getKnownStatus().getName(); value = nodeData.getKnown().getName();
break; break;
case COMMENT: case COMMENT:
value = eamArtifactInstance.getComment(); value = nodeData.getComment();
break; break;
} }
return value; 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 * @param newNodeData data to add to the table
* table
*/ */
public void addEamArtifact(CorrelationAttribute eamArtifact) { void addNodeData(OtherOccurrenceNodeData newNodeData) {
eamArtifacts.add(eamArtifact); nodeDataList.add(newNodeData);
fireTableDataChanged(); fireTableDataChanged();
} }
public void clearTable() { void clearTable() {
eamArtifacts.clear(); nodeDataList.clear();
fireTableDataChanged(); fireTableDataChanged();
} }

View File

@ -0,0 +1,233 @@
/*
* Central Repository
*
* Copyright 2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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 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;
}
}

View File

@ -1772,7 +1772,7 @@ abstract class AbstractSqlEamDb implements EamDb {
} catch (SQLException ex) { } catch (SQLException ex) {
throw new EamDbException("Error getting all artifact instances from instances table", ex); throw new EamDbException("Error getting all artifact instances from instances table", ex);
} finally { } finally {
EamDbUtil.closePreparedStatement(preparedStatement); EamDbUtil.closeStatement(preparedStatement);
EamDbUtil.closeResultSet(resultSet); EamDbUtil.closeResultSet(resultSet);
EamDbUtil.closeConnection(conn); EamDbUtil.closeConnection(conn);
} }

View File

@ -221,7 +221,7 @@ public final class PostgresEamDbSettings {
LOGGER.log(Level.SEVERE, "Failed to execute database existance query.", ex); // NON-NLS LOGGER.log(Level.SEVERE, "Failed to execute database existance query.", ex); // NON-NLS
return false; return false;
} finally { } finally {
EamDbUtil.closePreparedStatement(ps); EamDbUtil.closeStatement(ps);
EamDbUtil.closeResultSet(rs); EamDbUtil.closeResultSet(rs);
EamDbUtil.closeConnection(conn); EamDbUtil.closeConnection(conn);
} }