Autopsy  4.9.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
DataContentViewerOtherCases.java
Go to the documentation of this file.
1 /*
2  * Central Repository
3  *
4  * Copyright 2015-2018 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.centralrepository.contentviewer;
20 
21 import java.awt.Component;
22 import java.awt.FontMetrics;
23 import java.awt.event.ActionEvent;
24 import java.awt.event.ActionListener;
25 import java.io.BufferedWriter;
26 import java.io.File;
27 import java.io.IOException;
28 import java.nio.file.Files;
29 import java.text.DateFormat;
30 import java.text.ParseException;
31 import java.text.SimpleDateFormat;
32 import java.util.ArrayList;
33 import java.util.Calendar;
34 import java.util.Collection;
35 import java.util.HashMap;
36 import java.util.List;
37 import java.util.Locale;
38 import java.util.Map;
39 import java.util.Objects;
40 import java.util.logging.Level;
42 import javax.swing.JFileChooser;
43 import javax.swing.JMenuItem;
44 import javax.swing.JOptionPane;
45 import static javax.swing.JOptionPane.DEFAULT_OPTION;
46 import static javax.swing.JOptionPane.PLAIN_MESSAGE;
47 import static javax.swing.JOptionPane.ERROR_MESSAGE;
48 import javax.swing.JPanel;
49 import javax.swing.filechooser.FileNameExtensionFilter;
50 import javax.swing.table.TableCellRenderer;
51 import javax.swing.table.TableColumn;
52 import org.joda.time.DateTimeZone;
53 import org.joda.time.LocalDateTime;
54 import org.openide.nodes.Node;
55 import org.openide.util.NbBundle.Messages;
56 import org.openide.util.lookup.ServiceProvider;
66 import org.sleuthkit.datamodel.AbstractFile;
67 import org.sleuthkit.datamodel.BlackboardArtifact;
68 import org.sleuthkit.datamodel.BlackboardArtifactTag;
69 import org.sleuthkit.datamodel.Content;
70 import org.sleuthkit.datamodel.ContentTag;
71 import org.sleuthkit.datamodel.TskCoreException;
72 import org.sleuthkit.datamodel.TskException;
75 import org.sleuthkit.datamodel.SleuthkitCase;
76 import org.sleuthkit.datamodel.TskData;
77 
81 @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
82 @ServiceProvider(service = DataContentViewer.class, position = 9)
83 @Messages({"DataContentViewerOtherCases.title=Other Occurrences",
84  "DataContentViewerOtherCases.toolTip=Displays instances of the selected file/artifact from other occurrences.",})
85 public class DataContentViewerOtherCases extends JPanel implements DataContentViewer {
86 
87  private static final long serialVersionUID = -1L;
88 
89  private static final Logger LOGGER = Logger.getLogger(DataContentViewerOtherCases.class.getName());
90 
91  private static final int DEFAULT_MIN_CELL_WIDTH = 15;
92  private static final int CELL_TEXT_WIDTH_PADDING = 5;
93 
95  private final Collection<CorrelationAttributeInstance> correlationAttributes;
99  private AbstractFile file;
100 
105  this.tableModel = new DataContentViewerOtherCasesTableModel();
106  this.correlationAttributes = new ArrayList<>();
107 
108  initComponents();
109  customizeComponents();
110  reset();
111  }
112 
113  private void customizeComponents() {
114  ActionListener actList = new ActionListener() {
115  @Override
116  public void actionPerformed(ActionEvent e) {
117  JMenuItem jmi = (JMenuItem) e.getSource();
118  if (jmi.equals(selectAllMenuItem)) {
119  otherCasesTable.selectAll();
120  } else if (jmi.equals(showCaseDetailsMenuItem)) {
121  showCaseDetails(otherCasesTable.getSelectedRow());
122  } else if (jmi.equals(exportToCSVMenuItem)) {
123  try {
124  saveToCSV();
125  } catch (NoCurrentCaseException ex) {
126  LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
127  }
128  } else if (jmi.equals(showCommonalityMenuItem)) {
129  showCommonalityDetails();
130  }
131  }
132  };
133 
134  exportToCSVMenuItem.addActionListener(actList);
135  selectAllMenuItem.addActionListener(actList);
136  showCaseDetailsMenuItem.addActionListener(actList);
137  showCommonalityMenuItem.addActionListener(actList);
138 
139  // Set background of every nth row as light grey.
140  TableCellRenderer renderer = new DataContentViewerOtherCasesTableCellRenderer();
141  otherCasesTable.setDefaultRenderer(Object.class, renderer);
142 
143  }
144 
145  @Messages({"DataContentViewerOtherCases.correlatedArtifacts.isEmpty=There are no files or artifacts to correlate.",
146  "# {0} - commonality percentage",
147  "# {1} - correlation type",
148  "# {2} - correlation value",
149  "DataContentViewerOtherCases.correlatedArtifacts.byType={0}% of data sources have {2} (type: {1})\n",
150  "DataContentViewerOtherCases.correlatedArtifacts.title=Attribute Frequency",
151  "DataContentViewerOtherCases.correlatedArtifacts.failed=Failed to get frequency details."})
156  private void showCommonalityDetails() {
157  if (correlationAttributes.isEmpty()) {
158  JOptionPane.showConfirmDialog(showCommonalityMenuItem,
159  Bundle.DataContentViewerOtherCases_correlatedArtifacts_isEmpty(),
160  Bundle.DataContentViewerOtherCases_correlatedArtifacts_title(),
161  DEFAULT_OPTION, PLAIN_MESSAGE);
162  } else {
163  StringBuilder msg = new StringBuilder(correlationAttributes.size());
164  int percentage;
165  try {
166  EamDb dbManager = EamDb.getInstance();
167  for (CorrelationAttributeInstance eamArtifact : correlationAttributes) {
168  try {
169  percentage = dbManager.getFrequencyPercentage(eamArtifact);
170  msg.append(Bundle.DataContentViewerOtherCases_correlatedArtifacts_byType(percentage,
171  eamArtifact.getCorrelationType().getDisplayName(),
172  eamArtifact.getCorrelationValue()));
174  LOGGER.log(Level.WARNING, String.format("Error getting commonality details for artifact with ID: %s.", eamArtifact.getID()), ex);
175  }
176  }
177  JOptionPane.showConfirmDialog(showCommonalityMenuItem,
178  msg.toString(),
179  Bundle.DataContentViewerOtherCases_correlatedArtifacts_title(),
180  DEFAULT_OPTION, PLAIN_MESSAGE);
181  } catch (EamDbException ex) {
182  LOGGER.log(Level.SEVERE, "Error getting commonality details.", ex);
183  JOptionPane.showConfirmDialog(showCommonalityMenuItem,
184  Bundle.DataContentViewerOtherCases_correlatedArtifacts_failed(),
185  Bundle.DataContentViewerOtherCases_correlatedArtifacts_title(),
186  DEFAULT_OPTION, ERROR_MESSAGE);
187  }
188  }
189  }
190 
191  @Messages({"DataContentViewerOtherCases.caseDetailsDialog.notSelected=No Row Selected",
192  "DataContentViewerOtherCases.caseDetailsDialog.noDetails=No details for this case.",
193  "DataContentViewerOtherCases.caseDetailsDialog.noDetailsReference=No case details for Global reference properties.",
194  "DataContentViewerOtherCases.caseDetailsDialog.noCaseNameError=Error",
195  "DataContentViewerOtherCases.noOpenCase.errMsg=No open case available."})
196  private void showCaseDetails(int selectedRowViewIdx) {
197 
198  String caseDisplayName = Bundle.DataContentViewerOtherCases_caseDetailsDialog_noCaseNameError();
199  try {
200  if (-1 != selectedRowViewIdx) {
201  EamDb dbManager = EamDb.getInstance();
202  int selectedRowModelIdx = otherCasesTable.convertRowIndexToModel(selectedRowViewIdx);
203  OtherOccurrenceNodeInstanceData nodeData = (OtherOccurrenceNodeInstanceData) tableModel.getRow(selectedRowModelIdx);
204  CorrelationCase eamCasePartial = nodeData.getCorrelationAttributeInstance().getCorrelationCase();
205  if (eamCasePartial == null) {
206  JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
207  Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetailsReference(),
208  caseDisplayName,
209  DEFAULT_OPTION, PLAIN_MESSAGE);
210  return;
211  }
212  caseDisplayName = eamCasePartial.getDisplayName();
213  // query case details
214  CorrelationCase eamCase = dbManager.getCaseByUUID(eamCasePartial.getCaseUUID());
215  if (eamCase == null) {
216  JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
217  Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetails(),
218  caseDisplayName,
219  DEFAULT_OPTION, PLAIN_MESSAGE);
220  return;
221  }
222 
223  // display case details
224  JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
226  caseDisplayName,
227  DEFAULT_OPTION, PLAIN_MESSAGE);
228  } else {
229  JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
230  Bundle.DataContentViewerOtherCases_caseDetailsDialog_notSelected(),
231  caseDisplayName,
232  DEFAULT_OPTION, PLAIN_MESSAGE);
233  }
234  } catch (EamDbException ex) {
235  LOGGER.log(Level.SEVERE, "Error loading case details", ex);
236  JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
237  Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetails(),
238  caseDisplayName,
239  DEFAULT_OPTION, PLAIN_MESSAGE);
240  }
241  }
242 
243  private void saveToCSV() throws NoCurrentCaseException {
244  if (0 != otherCasesTable.getSelectedRowCount()) {
245  Calendar now = Calendar.getInstance();
246  String fileName = String.format("%1$tY%1$tm%1$te%1$tI%1$tM%1$tS_other_data_sources.csv", now);
247  CSVFileChooser.setCurrentDirectory(new File(Case.getCurrentCaseThrows().getExportDirectory()));
248  CSVFileChooser.setSelectedFile(new File(fileName));
249  CSVFileChooser.setFileFilter(new FileNameExtensionFilter("csv file", "csv"));
250 
251  int returnVal = CSVFileChooser.showSaveDialog(otherCasesTable);
252  if (returnVal == JFileChooser.APPROVE_OPTION) {
253 
254  File selectedFile = CSVFileChooser.getSelectedFile();
255  if (!selectedFile.getName().endsWith(".csv")) { // NON-NLS
256  selectedFile = new File(selectedFile.toString() + ".csv"); // NON-NLS
257  }
258 
259  writeSelectedRowsToFileAsCSV(selectedFile);
260  }
261  }
262  }
263 
264  private void writeSelectedRowsToFileAsCSV(File destFile) {
265  StringBuilder content;
266  int[] selectedRowViewIndices = otherCasesTable.getSelectedRows();
267  int colCount = tableModel.getColumnCount();
268 
269  try (BufferedWriter writer = Files.newBufferedWriter(destFile.toPath())) {
270 
271  // write column names
272  content = new StringBuilder("");
273  for (int colIdx = 0; colIdx < colCount; colIdx++) {
274  content.append('"').append(tableModel.getColumnName(colIdx)).append('"');
275  if (colIdx < (colCount - 1)) {
276  content.append(",");
277  }
278  }
279 
280  content.append(System.getProperty("line.separator"));
281  writer.write(content.toString());
282 
283  // write rows
284  for (int rowViewIdx : selectedRowViewIndices) {
285  content = new StringBuilder("");
286  for (int colIdx = 0; colIdx < colCount; colIdx++) {
287  int rowModelIdx = otherCasesTable.convertRowIndexToModel(rowViewIdx);
288  content.append('"').append(tableModel.getValueAt(rowModelIdx, colIdx)).append('"');
289  if (colIdx < (colCount - 1)) {
290  content.append(",");
291  }
292  }
293  content.append(System.getProperty("line.separator"));
294  writer.write(content.toString());
295  }
296 
297  } catch (IOException ex) {
298  LOGGER.log(Level.SEVERE, "Error writing selected rows to CSV.", ex);
299  }
300  }
301 
305  private void reset() {
306  // start with empty table
307  tableModel.clearTable();
308  correlationAttributes.clear();
309  earliestCaseDate.setText(Bundle.DataContentViewerOtherCases_earliestCaseNotAvailable());
310  }
311 
312  @Override
313  public String getTitle() {
314  return Bundle.DataContentViewerOtherCases_title();
315  }
316 
317  @Override
318  public String getToolTip() {
319  return Bundle.DataContentViewerOtherCases_toolTip();
320  }
321 
322  @Override
324  return new DataContentViewerOtherCases();
325  }
326 
327  @Override
328  public Component getComponent() {
329  return this;
330  }
331 
332  @Override
333  public void resetComponent() {
334  reset();
335  }
336 
337  @Override
338  public int isPreferred(Node node) {
339  return 1;
340  }
341 
349  private BlackboardArtifact getBlackboardArtifactFromNode(Node node) {
350  BlackboardArtifactTag nodeBbArtifactTag = node.getLookup().lookup(BlackboardArtifactTag.class);
351  BlackboardArtifact nodeBbArtifact = node.getLookup().lookup(BlackboardArtifact.class);
352 
353  if (nodeBbArtifactTag != null) {
354  return nodeBbArtifactTag.getArtifact();
355  } else if (nodeBbArtifact != null) {
356  return nodeBbArtifact;
357  }
358 
359  return null;
360  }
361 
369  private AbstractFile getAbstractFileFromNode(Node node) {
370  BlackboardArtifactTag nodeBbArtifactTag = node.getLookup().lookup(BlackboardArtifactTag.class);
371  ContentTag nodeContentTag = node.getLookup().lookup(ContentTag.class);
372  BlackboardArtifact nodeBbArtifact = node.getLookup().lookup(BlackboardArtifact.class);
373  AbstractFile nodeAbstractFile = node.getLookup().lookup(AbstractFile.class);
374 
375  if (nodeBbArtifactTag != null) {
376  Content content = nodeBbArtifactTag.getContent();
377  if (content instanceof AbstractFile) {
378  return (AbstractFile) content;
379  }
380  } else if (nodeContentTag != null) {
381  Content content = nodeContentTag.getContent();
382  if (content instanceof AbstractFile) {
383  return (AbstractFile) content;
384  }
385  } else if (nodeBbArtifact != null) {
386  Content content;
387  try {
388  content = nodeBbArtifact.getSleuthkitCase().getContentById(nodeBbArtifact.getObjectID());
389  } catch (TskCoreException ex) {
390  LOGGER.log(Level.SEVERE, "Error retrieving blackboard artifact", ex); // NON-NLS
391  return null;
392  }
393 
394  if (content instanceof AbstractFile) {
395  return (AbstractFile) content;
396  }
397  } else if (nodeAbstractFile != null) {
398  return nodeAbstractFile;
399  }
400 
401  return null;
402  }
403 
412  private Collection<CorrelationAttributeInstance> getCorrelationAttributesFromNode(Node node) {
413  Collection<CorrelationAttributeInstance> ret = new ArrayList<>();
414 
415  // correlate on blackboard artifact attributes if they exist and supported
416  BlackboardArtifact bbArtifact = getBlackboardArtifactFromNode(node);
417  if (bbArtifact != null && EamDb.isEnabled()) {
418  ret.addAll(EamArtifactUtil.makeInstancesFromBlackboardArtifact(bbArtifact, false));
419  }
420 
421  // we can correlate based on the MD5 if it is enabled
422  if (this.file != null && EamDb.isEnabled() && this.file.getSize() > 0) {
423  try {
424 
426  String md5 = this.file.getMd5Hash();
427  if (md5 != null && !md5.isEmpty() && null != artifactTypes && !artifactTypes.isEmpty()) {
428  for (CorrelationAttributeInstance.Type aType : artifactTypes) {
429  if (aType.getId() == CorrelationAttributeInstance.FILES_TYPE_ID) {
431  try {
432  ret.add(new CorrelationAttributeInstance(
433  aType,
434  md5,
435  corCase,
436  CorrelationDataSource.fromTSKDataSource(corCase, file.getDataSource()),
437  file.getParentPath() + file.getName(),
438  "",
439  file.getKnown(),
440  file.getId()));
442  LOGGER.log(Level.INFO, String.format("Unable to check create CorrelationAttribtueInstance for value %s and type %s.", md5, aType.toString()), ex);
443  }
444  break;
445  }
446  }
447  }
448  } catch (EamDbException | TskCoreException ex) {
449  LOGGER.log(Level.SEVERE, "Error connecting to DB", ex); // NON-NLS
450  }
451  // If EamDb not enabled, get the Files default correlation type to allow Other Occurances to be enabled.
452  } else if (this.file != null && this.file.getSize() > 0) {
453  String md5 = this.file.getMd5Hash();
454  if (md5 != null && !md5.isEmpty()) {
455  try {
456  final CorrelationAttributeInstance.Type fileAttributeType
458  .stream()
459  .filter(attrType -> attrType.getId() == CorrelationAttributeInstance.FILES_TYPE_ID)
460  .findAny()
461  .get();
462  //The Central Repository is not enabled
463  ret.add(new CorrelationAttributeInstance(fileAttributeType, md5, null, null, "", "", TskData.FileKnown.UNKNOWN, this.file.getId()));
464  } catch (EamDbException ex) {
465  LOGGER.log(Level.SEVERE, "Error connecting to DB", ex); // NON-NLS
467  LOGGER.log(Level.INFO, String.format("Unable to create CorrelationAttributeInstance for value %s", md5), ex); // NON-NLS
468  }
469  }
470  }
471 
472  return ret;
473  }
474 
475  @Messages({"DataContentViewerOtherCases.earliestCaseNotAvailable= Not Enabled."})
480  private void setEarliestCaseDate() {
481  String dateStringDisplay = Bundle.DataContentViewerOtherCases_earliestCaseNotAvailable();
482 
483  if (EamDb.isEnabled()) {
484  LocalDateTime earliestDate = LocalDateTime.now(DateTimeZone.UTC);
485  DateFormat datetimeFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.US);
486  try {
487  EamDb dbManager = EamDb.getInstance();
488  List<CorrelationCase> cases = dbManager.getCases();
489  for (CorrelationCase aCase : cases) {
490  LocalDateTime caseDate = LocalDateTime.fromDateFields(datetimeFormat.parse(aCase.getCreationDate()));
491 
492  if (caseDate.isBefore(earliestDate)) {
493  earliestDate = caseDate;
494  dateStringDisplay = aCase.getCreationDate();
495  }
496 
497  }
498 
499  } catch (EamDbException ex) {
500  LOGGER.log(Level.SEVERE, "Error getting list of cases from database.", ex); // NON-NLS
501  } catch (ParseException ex) {
502  LOGGER.log(Level.SEVERE, "Error parsing date of cases from database.", ex); // NON-NLS
503  }
504 
505  }
506  earliestCaseDate.setText(dateStringDisplay);
507  }
508 
521  private Map<UniquePathKey, OtherOccurrenceNodeInstanceData> getCorrelatedInstances(CorrelationAttributeInstance corAttr, String dataSourceName, String deviceId) {
522  // @@@ Check exception
523  try {
524  final Case openCase = Case.getCurrentCase();
525  String caseUUID = openCase.getName();
526 
527  HashMap<UniquePathKey, OtherOccurrenceNodeInstanceData> nodeDataMap = new HashMap<>();
528 
529  if (EamDb.isEnabled()) {
530  List<CorrelationAttributeInstance> instances = EamDb.getInstance().getArtifactInstancesByTypeValue(corAttr.getCorrelationType(), corAttr.getCorrelationValue());
531 
532  for (CorrelationAttributeInstance artifactInstance : instances) {
533 
534  // Only add the attribute if it isn't the object the user selected.
535  // We consider it to be a different object if at least one of the following is true:
536  // - the case UUID is different
537  // - the data source name is different
538  // - the data source device ID is different
539  // - the file path is different
540  if (!artifactInstance.getCorrelationCase().getCaseUUID().equals(caseUUID)
541  || !artifactInstance.getCorrelationDataSource().getName().equals(dataSourceName)
542  || !artifactInstance.getCorrelationDataSource().getDeviceID().equals(deviceId)
543  || !artifactInstance.getFilePath().equalsIgnoreCase(file.getParentPath() + file.getName())) {
544 
545  OtherOccurrenceNodeInstanceData newNode = new OtherOccurrenceNodeInstanceData(artifactInstance, corAttr.getCorrelationType(), corAttr.getCorrelationValue());
546  UniquePathKey uniquePathKey = new UniquePathKey(newNode);
547  nodeDataMap.put(uniquePathKey, newNode);
548  }
549  }
550  }
551 
552  if (corAttr.getCorrelationType().getDisplayName().equals("Files")) {
553  List<AbstractFile> caseDbFiles = getCaseDbMatches(corAttr, openCase);
554 
555  for (AbstractFile caseDbFile : caseDbFiles) {
556  addOrUpdateNodeData(openCase, nodeDataMap, caseDbFile);
557  }
558  }
559 
560  return nodeDataMap;
561  } catch (EamDbException ex) {
562  LOGGER.log(Level.SEVERE, "Error getting artifact instances from database.", ex); // NON-NLS
564  LOGGER.log(Level.INFO, "Error getting artifact instances from database.", ex); // NON-NLS
565  } catch (NoCurrentCaseException ex) {
566  LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
567  } catch (TskCoreException ex) {
568  // do nothing.
569  // @@@ Review this behavior
570  LOGGER.log(Level.SEVERE, "Exception while querying open case.", ex); // NON-NLS
571  }
572 
573  return new HashMap<>(0);
574  }
575 
589  private List<AbstractFile> getCaseDbMatches(CorrelationAttributeInstance corAttr, Case openCase) throws NoCurrentCaseException, TskCoreException, EamDbException {
590  String md5 = corAttr.getCorrelationValue();
591  SleuthkitCase tsk = openCase.getSleuthkitCase();
592  List<AbstractFile> matches = tsk.findAllFilesWhere(String.format("md5 = '%s'", new Object[]{md5}));
593 
594  List<AbstractFile> caseDbArtifactInstances = new ArrayList<>();
595  for (AbstractFile fileMatch : matches) {
596  if (this.file.equals(fileMatch)) {
597  continue; // If this is the file the user clicked on
598  }
599  caseDbArtifactInstances.add(fileMatch);
600  }
601  return caseDbArtifactInstances;
602 
603  }
604 
615  private void addOrUpdateNodeData(final Case autopsyCase, Map<UniquePathKey, OtherOccurrenceNodeInstanceData> nodeDataMap, AbstractFile newFile) throws TskCoreException, EamDbException {
616 
617  OtherOccurrenceNodeInstanceData newNode = new OtherOccurrenceNodeInstanceData(newFile, autopsyCase);
618 
619  // If the caseDB object has a notable tag associated with it, update
620  // the known status to BAD
621  if (newNode.getKnown() != TskData.FileKnown.BAD) {
622  List<ContentTag> fileMatchTags = autopsyCase.getServices().getTagsManager().getContentTagsByContent(newFile);
623  for (ContentTag tag : fileMatchTags) {
624  TskData.FileKnown tagKnownStatus = tag.getName().getKnownStatus();
625  if (tagKnownStatus.equals(TskData.FileKnown.BAD)) {
626  newNode.updateKnown(TskData.FileKnown.BAD);
627  break;
628  }
629  }
630  }
631 
632  // Make a key to see if the file is already in the map
633  UniquePathKey uniquePathKey = new UniquePathKey(newNode);
634 
635  // If this node is already in the list, the only thing we need to do is
636  // update the known status to BAD if the caseDB version had known status BAD.
637  // Otherwise this is a new node so add the new node to the map.
638  if (nodeDataMap.containsKey(uniquePathKey)) {
639  if (newNode.getKnown() == TskData.FileKnown.BAD) {
640  OtherOccurrenceNodeInstanceData prevInstance = nodeDataMap.get(uniquePathKey);
641  prevInstance.updateKnown(newNode.getKnown());
642  }
643  } else {
644  nodeDataMap.put(uniquePathKey, newNode);
645  }
646  }
647 
648  @Override
649  public boolean isSupported(Node node) {
650 
651  // Is supported if one of the following is true:
652  // - The central repo is enabled and the node has correlatable content
653  // (either through the MD5 hash of the associated file or through a BlackboardArtifact)
654  // - The central repo is disabled and the backing file has a valid MD5 hash
655  this.file = this.getAbstractFileFromNode(node);
656  if (EamDb.isEnabled()) {
657  return !getCorrelationAttributesFromNode(node).isEmpty();
658  } else {
659  return this.file != null
660  && this.file.getSize() > 0
661  && ((this.file.getMd5Hash() != null) && (!this.file.getMd5Hash().isEmpty()));
662  }
663  }
664 
665  @Override
666  @Messages({"DataContentViewerOtherCases.table.nodbconnection=Cannot connect to central repository database."})
667  public void setNode(Node node) {
668 
669  reset(); // reset the table to empty.
670  if (node == null) {
671  return;
672  }
673  //could be null
674  this.file = this.getAbstractFileFromNode(node);
675  populateTable(node);
676  }
677 
684  @Messages({
685  "DataContentViewerOtherCases.table.noArtifacts=Item has no attributes with which to search.",
686  "DataContentViewerOtherCases.table.noResultsFound=No results found."
687  })
688  private void populateTable(Node node) {
689  String dataSourceName = "";
690  String deviceId = "";
691  try {
692  if (this.file != null) {
693  Content dataSource = this.file.getDataSource();
694  dataSourceName = dataSource.getName();
695  deviceId = Case.getCurrentCaseThrows().getSleuthkitCase().getDataSource(dataSource.getId()).getDeviceId();
696  }
697  } catch (TskException | NoCurrentCaseException ex) {
698  // do nothing.
699  // @@@ Review this behavior
700  }
701 
702  // get the attributes we can correlate on
703  correlationAttributes.addAll(getCorrelationAttributesFromNode(node));
704  for (CorrelationAttributeInstance corAttr : correlationAttributes) {
705  Map<UniquePathKey, OtherOccurrenceNodeInstanceData> correlatedNodeDataMap = new HashMap<>(0);
706 
707  // get correlation and reference set instances from DB
708  correlatedNodeDataMap.putAll(getCorrelatedInstances(corAttr, dataSourceName, deviceId));
709 
710  correlatedNodeDataMap.values().forEach((nodeData) -> {
711  tableModel.addNodeData(nodeData);
712  });
713  }
714 
715  if (correlationAttributes.isEmpty()) {
716  tableModel.addNodeData(new OtherOccurrenceNodeMessageData(Bundle.DataContentViewerOtherCases_table_noArtifacts()));
717  setColumnWidthToText(0, Bundle.DataContentViewerOtherCases_table_noArtifacts());
718  } else if (0 == tableModel.getRowCount()) {
719  tableModel.addNodeData(new OtherOccurrenceNodeMessageData(Bundle.DataContentViewerOtherCases_table_noResultsFound()));
720  setColumnWidthToText(0, Bundle.DataContentViewerOtherCases_table_noResultsFound());
721  } else {
722  setColumnWidths();
723  }
724  setEarliestCaseDate();
725  }
726 
734  private void setColumnWidthToText(int columnIndex, String text) {
735  TableColumn column = otherCasesTable.getColumnModel().getColumn(columnIndex);
736  FontMetrics fontMetrics = otherCasesTable.getFontMetrics(otherCasesTable.getFont());
737  int stringWidth = fontMetrics.stringWidth(text);
738  column.setMinWidth(stringWidth + CELL_TEXT_WIDTH_PADDING);
739  }
740 
744  private void setColumnWidths() {
745  for (int idx = 0; idx < tableModel.getColumnCount(); idx++) {
746  TableColumn column = otherCasesTable.getColumnModel().getColumn(idx);
747  column.setMinWidth(DEFAULT_MIN_CELL_WIDTH);
748  int columnWidth = tableModel.getColumnPreferredWidth(idx);
749  if (columnWidth > 0) {
750  column.setPreferredWidth(columnWidth);
751  }
752  }
753  }
754 
760  @SuppressWarnings("unchecked")
761  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
762  private void initComponents() {
763 
764  rightClickPopupMenu = new javax.swing.JPopupMenu();
765  selectAllMenuItem = new javax.swing.JMenuItem();
766  exportToCSVMenuItem = new javax.swing.JMenuItem();
767  showCaseDetailsMenuItem = new javax.swing.JMenuItem();
768  showCommonalityMenuItem = new javax.swing.JMenuItem();
769  CSVFileChooser = new javax.swing.JFileChooser();
770  otherCasesPanel = new javax.swing.JPanel();
771  tableContainerPanel = new javax.swing.JPanel();
772  tableScrollPane = new javax.swing.JScrollPane();
773  otherCasesTable = new javax.swing.JTable();
774  earliestCaseLabel = new javax.swing.JLabel();
775  earliestCaseDate = new javax.swing.JLabel();
776  tableStatusPanel = new javax.swing.JPanel();
777 
778  rightClickPopupMenu.addPopupMenuListener(new javax.swing.event.PopupMenuListener() {
779  public void popupMenuCanceled(javax.swing.event.PopupMenuEvent evt) {
780  }
781  public void popupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent evt) {
782  }
783  public void popupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent evt) {
784  rightClickPopupMenuPopupMenuWillBecomeVisible(evt);
785  }
786  });
787 
788  org.openide.awt.Mnemonics.setLocalizedText(selectAllMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.selectAllMenuItem.text")); // NOI18N
789  rightClickPopupMenu.add(selectAllMenuItem);
790 
791  org.openide.awt.Mnemonics.setLocalizedText(exportToCSVMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.exportToCSVMenuItem.text")); // NOI18N
792  rightClickPopupMenu.add(exportToCSVMenuItem);
793 
794  org.openide.awt.Mnemonics.setLocalizedText(showCaseDetailsMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.showCaseDetailsMenuItem.text")); // NOI18N
795  rightClickPopupMenu.add(showCaseDetailsMenuItem);
796 
797  org.openide.awt.Mnemonics.setLocalizedText(showCommonalityMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.showCommonalityMenuItem.text")); // NOI18N
798  rightClickPopupMenu.add(showCommonalityMenuItem);
799 
800  setMinimumSize(new java.awt.Dimension(1500, 10));
801  setOpaque(false);
802  setPreferredSize(new java.awt.Dimension(1500, 44));
803 
804  otherCasesPanel.setPreferredSize(new java.awt.Dimension(1500, 144));
805 
806  tableContainerPanel.setPreferredSize(new java.awt.Dimension(1500, 63));
807 
808  tableScrollPane.setPreferredSize(new java.awt.Dimension(1500, 30));
809 
810  otherCasesTable.setAutoCreateRowSorter(true);
811  otherCasesTable.setModel(tableModel);
812  otherCasesTable.setToolTipText(org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.table.toolTip.text")); // NOI18N
813  otherCasesTable.setComponentPopupMenu(rightClickPopupMenu);
814  otherCasesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_INTERVAL_SELECTION);
815  tableScrollPane.setViewportView(otherCasesTable);
816 
817  org.openide.awt.Mnemonics.setLocalizedText(earliestCaseLabel, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.earliestCaseLabel.text")); // NOI18N
818  earliestCaseLabel.setToolTipText(org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.earliestCaseLabel.toolTipText")); // NOI18N
819 
820  org.openide.awt.Mnemonics.setLocalizedText(earliestCaseDate, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.earliestCaseDate.text")); // NOI18N
821 
822  tableStatusPanel.setPreferredSize(new java.awt.Dimension(1500, 16));
823 
824  javax.swing.GroupLayout tableStatusPanelLayout = new javax.swing.GroupLayout(tableStatusPanel);
825  tableStatusPanel.setLayout(tableStatusPanelLayout);
826  tableStatusPanelLayout.setHorizontalGroup(
827  tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
828  .addGap(0, 0, Short.MAX_VALUE)
829  );
830  tableStatusPanelLayout.setVerticalGroup(
831  tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
832  .addGap(0, 16, Short.MAX_VALUE)
833  );
834 
835  javax.swing.GroupLayout tableContainerPanelLayout = new javax.swing.GroupLayout(tableContainerPanel);
836  tableContainerPanel.setLayout(tableContainerPanelLayout);
837  tableContainerPanelLayout.setHorizontalGroup(
838  tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
839  .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, tableContainerPanelLayout.createSequentialGroup()
840  .addComponent(tableStatusPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 1282, Short.MAX_VALUE)
841  .addGap(218, 218, 218))
842  .addComponent(tableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
843  .addGroup(tableContainerPanelLayout.createSequentialGroup()
844  .addComponent(earliestCaseLabel)
845  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
846  .addComponent(earliestCaseDate)
847  .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
848  );
849  tableContainerPanelLayout.setVerticalGroup(
850  tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
851  .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, tableContainerPanelLayout.createSequentialGroup()
852  .addComponent(tableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 27, Short.MAX_VALUE)
853  .addGap(2, 2, 2)
854  .addGroup(tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
855  .addComponent(earliestCaseLabel)
856  .addComponent(earliestCaseDate))
857  .addGap(0, 0, 0)
858  .addComponent(tableStatusPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
859  .addGap(0, 0, 0))
860  );
861 
862  javax.swing.GroupLayout otherCasesPanelLayout = new javax.swing.GroupLayout(otherCasesPanel);
863  otherCasesPanel.setLayout(otherCasesPanelLayout);
864  otherCasesPanelLayout.setHorizontalGroup(
865  otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
866  .addGap(0, 1500, Short.MAX_VALUE)
867  .addGroup(otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
868  .addComponent(tableContainerPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
869  );
870  otherCasesPanelLayout.setVerticalGroup(
871  otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
872  .addGap(0, 483, Short.MAX_VALUE)
873  .addGroup(otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
874  .addGroup(otherCasesPanelLayout.createSequentialGroup()
875  .addComponent(tableContainerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 59, Short.MAX_VALUE)
876  .addGap(0, 0, 0)))
877  );
878 
879  javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
880  this.setLayout(layout);
881  layout.setHorizontalGroup(
882  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
883  .addComponent(otherCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
884  );
885  layout.setVerticalGroup(
886  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
887  .addComponent(otherCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 59, Short.MAX_VALUE)
888  );
889  }// </editor-fold>//GEN-END:initComponents
890 
891  private void rightClickPopupMenuPopupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent evt) {//GEN-FIRST:event_rightClickPopupMenuPopupMenuWillBecomeVisible
892  boolean enableCentralRepoActions = false;
893 
894  if (EamDbUtil.useCentralRepo() && otherCasesTable.getSelectedRowCount() == 1) {
895  int rowIndex = otherCasesTable.getSelectedRow();
896  OtherOccurrenceNodeData selectedNode = (OtherOccurrenceNodeData) tableModel.getRow(rowIndex);
897  if (selectedNode instanceof OtherOccurrenceNodeInstanceData) {
898  OtherOccurrenceNodeInstanceData instanceData = (OtherOccurrenceNodeInstanceData) selectedNode;
899  enableCentralRepoActions = instanceData.isCentralRepoNode();
900  }
901  }
902  showCaseDetailsMenuItem.setVisible(enableCentralRepoActions);
903  showCommonalityMenuItem.setVisible(enableCentralRepoActions);
904  }//GEN-LAST:event_rightClickPopupMenuPopupMenuWillBecomeVisible
905 
906  // Variables declaration - do not modify//GEN-BEGIN:variables
907  private javax.swing.JFileChooser CSVFileChooser;
908  private javax.swing.JLabel earliestCaseDate;
909  private javax.swing.JLabel earliestCaseLabel;
910  private javax.swing.JMenuItem exportToCSVMenuItem;
911  private javax.swing.JPanel otherCasesPanel;
912  private javax.swing.JTable otherCasesTable;
913  private javax.swing.JPopupMenu rightClickPopupMenu;
914  private javax.swing.JMenuItem selectAllMenuItem;
915  private javax.swing.JMenuItem showCaseDetailsMenuItem;
916  private javax.swing.JMenuItem showCommonalityMenuItem;
917  private javax.swing.JPanel tableContainerPanel;
918  private javax.swing.JScrollPane tableScrollPane;
919  private javax.swing.JPanel tableStatusPanel;
920  // End of variables declaration//GEN-END:variables
921 
926  private static final class UniquePathKey {
927 
928  private final String dataSourceID;
929  private final String filePath;
930  private final String type;
931 
932  UniquePathKey(OtherOccurrenceNodeInstanceData nodeData) {
933  super();
934  dataSourceID = nodeData.getDeviceID();
935  if (nodeData.getFilePath() != null) {
936  filePath = nodeData.getFilePath().toLowerCase();
937  } else {
938  filePath = null;
939  }
940  type = nodeData.getType();
941  }
942 
943  @Override
944  public boolean equals(Object other) {
945  if (other instanceof UniquePathKey) {
946  UniquePathKey otherKey = (UniquePathKey) (other);
947  return (Objects.equals(otherKey.getDataSourceID(), this.getDataSourceID())
948  && Objects.equals(otherKey.getFilePath(), this.getFilePath())
949  && Objects.equals(otherKey.getType(), this.getType()));
950  }
951  return false;
952  }
953 
954  @Override
955  public int hashCode() {
956  //int hash = 7;
957  //hash = 67 * hash + this.dataSourceID.hashCode();
958  //hash = 67 * hash + this.filePath.hashCode();
959  return Objects.hash(getDataSourceID(), getFilePath(), getType());
960  }
961 
967  String getType() {
968  return type;
969  }
970 
976  String getFilePath() {
977  return filePath;
978  }
979 
985  String getDataSourceID() {
986  return dataSourceID;
987  }
988  }
989 }
static List< CorrelationAttributeInstance > makeInstancesFromBlackboardArtifact(BlackboardArtifact artifact, boolean checkEnabled)
CorrelationCase getCaseByUUID(String caseUUID)
int getFrequencyPercentage(CorrelationAttributeInstance corAttr)
static CorrelationDataSource fromTSKDataSource(CorrelationCase correlationCase, Content dataSource)
List< CorrelationAttributeInstance > getArtifactInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String value)
List< CorrelationAttributeInstance.Type > getDefinedCorrelationTypes()
void addOrUpdateNodeData(final Case autopsyCase, Map< UniquePathKey, OtherOccurrenceNodeInstanceData > nodeDataMap, AbstractFile newFile)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
List< AbstractFile > getCaseDbMatches(CorrelationAttributeInstance corAttr, Case openCase)
Map< UniquePathKey, OtherOccurrenceNodeInstanceData > getCorrelatedInstances(CorrelationAttributeInstance corAttr, String dataSourceName, String deviceId)

Copyright © 2012-2018 Basis Technology. Generated on: Tue Dec 18 2018
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.