Autopsy  4.8.0
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()) {
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  md5,
434  aType,
435  corCase,
436  CorrelationDataSource.fromTSKDataSource(corCase, file.getDataSource()),
437  file.getParentPath() + file.getName(),
438  "",
439  file.getKnown()));
441  LOGGER.log(Level.INFO, String.format("Unable to check create CorrelationAttribtueInstance for value %s and type %s.", md5, aType.toString()), ex);
442  }
443  break;
444  }
445  }
446  }
447  } catch (EamDbException | TskCoreException ex) {
448  LOGGER.log(Level.SEVERE, "Error connecting to DB", ex); // NON-NLS
449  }
450 
451  } else {
452 
453  // If EamDb not enabled, get the Files default correlation type to allow Other Occurances to be enabled.
454  if (this.file != null) {
455  String md5 = this.file.getMd5Hash();
456  if (md5 != null && !md5.isEmpty()) {
457  try {
458  final CorrelationAttributeInstance.Type fileAttributeType
460  .stream()
461  .filter(attrType -> attrType.getId() == CorrelationAttributeInstance.FILES_TYPE_ID)
462  .findAny()
463  .get();
464 
465  ret.add(new CorrelationAttributeInstance(fileAttributeType, md5));
466  } catch (EamDbException ex) {
467  LOGGER.log(Level.SEVERE, "Error connecting to DB", ex); // NON-NLS
469  LOGGER.log(Level.INFO, String.format("Unable to create CorrelationAttributeInstance for value %s", md5), ex); // NON-NLS
470  }
471  }
472  }
473  }
474 
475  return ret;
476  }
477 
478  @Messages({"DataContentViewerOtherCases.earliestCaseNotAvailable= Not Enabled."})
483  private void setEarliestCaseDate() {
484  String dateStringDisplay = Bundle.DataContentViewerOtherCases_earliestCaseNotAvailable();
485 
486  if (EamDb.isEnabled()) {
487  LocalDateTime earliestDate = LocalDateTime.now(DateTimeZone.UTC);
488  DateFormat datetimeFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.US);
489  try {
490  EamDb dbManager = EamDb.getInstance();
491  List<CorrelationCase> cases = dbManager.getCases();
492  for (CorrelationCase aCase : cases) {
493  LocalDateTime caseDate = LocalDateTime.fromDateFields(datetimeFormat.parse(aCase.getCreationDate()));
494 
495  if (caseDate.isBefore(earliestDate)) {
496  earliestDate = caseDate;
497  dateStringDisplay = aCase.getCreationDate();
498  }
499 
500  }
501 
502  } catch (EamDbException ex) {
503  LOGGER.log(Level.SEVERE, "Error getting list of cases from database.", ex); // NON-NLS
504  } catch (ParseException ex) {
505  LOGGER.log(Level.SEVERE, "Error parsing date of cases from database.", ex); // NON-NLS
506  }
507 
508  }
509  earliestCaseDate.setText(dateStringDisplay);
510  }
511 
524  private Map<UniquePathKey, OtherOccurrenceNodeInstanceData> getCorrelatedInstances(CorrelationAttributeInstance corAttr, String dataSourceName, String deviceId) {
525  // @@@ Check exception
526  try {
527  final Case openCase = Case.getCurrentCase();
528  String caseUUID = openCase.getName();
529 
530  HashMap<UniquePathKey, OtherOccurrenceNodeInstanceData> nodeDataMap = new HashMap<>();
531 
532  if (EamDb.isEnabled()) {
533  List<CorrelationAttributeInstance> instances = EamDb.getInstance().getArtifactInstancesByTypeValue(corAttr.getCorrelationType(), corAttr.getCorrelationValue());
534 
535  for (CorrelationAttributeInstance artifactInstance : instances) {
536 
537  // Only add the attribute if it isn't the object the user selected.
538  // We consider it to be a different object if at least one of the following is true:
539  // - the case UUID is different
540  // - the data source name is different
541  // - the data source device ID is different
542  // - the file path is different
543  if (!artifactInstance.getCorrelationCase().getCaseUUID().equals(caseUUID)
544  || !artifactInstance.getCorrelationDataSource().getName().equals(dataSourceName)
545  || !artifactInstance.getCorrelationDataSource().getDeviceID().equals(deviceId)
546  || !artifactInstance.getFilePath().equalsIgnoreCase(file.getParentPath() + file.getName())) {
547 
548  OtherOccurrenceNodeInstanceData newNode = new OtherOccurrenceNodeInstanceData(artifactInstance, corAttr.getCorrelationType(), corAttr.getCorrelationValue());
549  UniquePathKey uniquePathKey = new UniquePathKey(newNode);
550  nodeDataMap.put(uniquePathKey, newNode);
551  }
552  }
553  }
554 
555  if (corAttr.getCorrelationType().getDisplayName().equals("Files")) {
556  List<AbstractFile> caseDbFiles = getCaseDbMatches(corAttr, openCase);
557 
558  for (AbstractFile caseDbFile : caseDbFiles) {
559  addOrUpdateNodeData(openCase, nodeDataMap, caseDbFile);
560  }
561  }
562 
563  return nodeDataMap;
564  } catch (EamDbException ex) {
565  LOGGER.log(Level.SEVERE, "Error getting artifact instances from database.", ex); // NON-NLS
567  LOGGER.log(Level.INFO, "Error getting artifact instances from database.", ex); // NON-NLS
568  } catch (NoCurrentCaseException ex) {
569  LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
570  } catch (TskCoreException ex) {
571  // do nothing.
572  // @@@ Review this behavior
573  LOGGER.log(Level.SEVERE, "Exception while querying open case.", ex); // NON-NLS
574  }
575 
576  return new HashMap<>(0);
577  }
578 
592  private List<AbstractFile> getCaseDbMatches(CorrelationAttributeInstance corAttr, Case openCase) throws NoCurrentCaseException, TskCoreException, EamDbException {
593  String md5 = corAttr.getCorrelationValue();
594  SleuthkitCase tsk = openCase.getSleuthkitCase();
595  List<AbstractFile> matches = tsk.findAllFilesWhere(String.format("md5 = '%s'", new Object[]{md5}));
596 
597  List<AbstractFile> caseDbArtifactInstances = new ArrayList<>();
598  for (AbstractFile fileMatch : matches) {
599  if (this.file.equals(fileMatch)) {
600  continue; // If this is the file the user clicked on
601  }
602  caseDbArtifactInstances.add(fileMatch);
603  }
604  return caseDbArtifactInstances;
605 
606  }
607 
618  private void addOrUpdateNodeData(final Case autopsyCase, Map<UniquePathKey, OtherOccurrenceNodeInstanceData> nodeDataMap, AbstractFile newFile) throws TskCoreException, EamDbException {
619 
620  OtherOccurrenceNodeInstanceData newNode = new OtherOccurrenceNodeInstanceData(newFile, autopsyCase);
621 
622  // If the caseDB object has a notable tag associated with it, update
623  // the known status to BAD
624  if (newNode.getKnown() != TskData.FileKnown.BAD) {
625  List<ContentTag> fileMatchTags = autopsyCase.getServices().getTagsManager().getContentTagsByContent(newFile);
626  for (ContentTag tag : fileMatchTags) {
627  TskData.FileKnown tagKnownStatus = tag.getName().getKnownStatus();
628  if (tagKnownStatus.equals(TskData.FileKnown.BAD)) {
629  newNode.updateKnown(TskData.FileKnown.BAD);
630  break;
631  }
632  }
633  }
634 
635  // Make a key to see if the file is already in the map
636  UniquePathKey uniquePathKey = new UniquePathKey(newNode);
637 
638  // If this node is already in the list, the only thing we need to do is
639  // update the known status to BAD if the caseDB version had known status BAD.
640  // Otherwise this is a new node so add the new node to the map.
641  if (nodeDataMap.containsKey(uniquePathKey)) {
642  if (newNode.getKnown() == TskData.FileKnown.BAD) {
643  OtherOccurrenceNodeInstanceData prevInstance = nodeDataMap.get(uniquePathKey);
644  prevInstance.updateKnown(newNode.getKnown());
645  }
646  } else {
647  nodeDataMap.put(uniquePathKey, newNode);
648  }
649  }
650 
651  @Override
652  public boolean isSupported(Node node) {
653 
654  // Is supported if one of the following is true:
655  // - The central repo is enabled and the node has correlatable content
656  // (either through the MD5 hash of the associated file or through a BlackboardArtifact)
657  // - The central repo is disabled and the backing file has a valid MD5 hash
658  this.file = this.getAbstractFileFromNode(node);
659  if (EamDb.isEnabled()) {
660  return this.file != null
661  && this.file.getSize() > 0
662  && !getCorrelationAttributesFromNode(node).isEmpty();
663  } else {
664  return this.file != null
665  && this.file.getSize() > 0
666  && ((this.file.getMd5Hash() != null) && (!this.file.getMd5Hash().isEmpty()));
667  }
668  }
669 
670  @Override
671  @Messages({"DataContentViewerOtherCases.table.nodbconnection=Cannot connect to central repository database."})
672  public void setNode(Node node) {
673 
674  reset(); // reset the table to empty.
675  if (node == null) {
676  return;
677  }
678  //could be null
679  this.file = this.getAbstractFileFromNode(node);
680  populateTable(node);
681  }
682 
689  @Messages({
690  "DataContentViewerOtherCases.table.noArtifacts=Item has no attributes with which to search.",
691  "DataContentViewerOtherCases.table.noResultsFound=No results found."
692  })
693  private void populateTable(Node node) {
694  String dataSourceName = "";
695  String deviceId = "";
696  try {
697  if (this.file != null) {
698  Content dataSource = this.file.getDataSource();
699  dataSourceName = dataSource.getName();
700  deviceId = Case.getCurrentCaseThrows().getSleuthkitCase().getDataSource(dataSource.getId()).getDeviceId();
701  }
702  } catch (TskException | NoCurrentCaseException ex) {
703  // do nothing.
704  // @@@ Review this behavior
705  }
706 
707  // get the attributes we can correlate on
708  correlationAttributes.addAll(getCorrelationAttributesFromNode(node));
709  for (CorrelationAttributeInstance corAttr : correlationAttributes) {
710  Map<UniquePathKey, OtherOccurrenceNodeInstanceData> correlatedNodeDataMap = new HashMap<>(0);
711 
712  // get correlation and reference set instances from DB
713  correlatedNodeDataMap.putAll(getCorrelatedInstances(corAttr, dataSourceName, deviceId));
714 
715  correlatedNodeDataMap.values().forEach((nodeData) -> {
716  tableModel.addNodeData(nodeData);
717  });
718  }
719 
720  if (correlationAttributes.isEmpty()) {
721  tableModel.addNodeData(new OtherOccurrenceNodeMessageData(Bundle.DataContentViewerOtherCases_table_noArtifacts()));
722  setColumnWidthToText(0, Bundle.DataContentViewerOtherCases_table_noArtifacts());
723  } else if (0 == tableModel.getRowCount()) {
724  tableModel.addNodeData(new OtherOccurrenceNodeMessageData(Bundle.DataContentViewerOtherCases_table_noResultsFound()));
725  setColumnWidthToText(0, Bundle.DataContentViewerOtherCases_table_noResultsFound());
726  } else {
727  setColumnWidths();
728  }
729  setEarliestCaseDate();
730  }
731 
739  private void setColumnWidthToText(int columnIndex, String text) {
740  TableColumn column = otherCasesTable.getColumnModel().getColumn(columnIndex);
741  FontMetrics fontMetrics = otherCasesTable.getFontMetrics(otherCasesTable.getFont());
742  int stringWidth = fontMetrics.stringWidth(text);
743  column.setMinWidth(stringWidth + CELL_TEXT_WIDTH_PADDING);
744  }
745 
749  private void setColumnWidths() {
750  for (int idx = 0; idx < tableModel.getColumnCount(); idx++) {
751  TableColumn column = otherCasesTable.getColumnModel().getColumn(idx);
752  column.setMinWidth(DEFAULT_MIN_CELL_WIDTH);
753  int columnWidth = tableModel.getColumnPreferredWidth(idx);
754  if (columnWidth > 0) {
755  column.setPreferredWidth(columnWidth);
756  }
757  }
758  }
759 
765  @SuppressWarnings("unchecked")
766  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
767  private void initComponents() {
768 
769  rightClickPopupMenu = new javax.swing.JPopupMenu();
770  selectAllMenuItem = new javax.swing.JMenuItem();
771  exportToCSVMenuItem = new javax.swing.JMenuItem();
772  showCaseDetailsMenuItem = new javax.swing.JMenuItem();
773  showCommonalityMenuItem = new javax.swing.JMenuItem();
774  CSVFileChooser = new javax.swing.JFileChooser();
775  otherCasesPanel = new javax.swing.JPanel();
776  tableContainerPanel = new javax.swing.JPanel();
777  tableScrollPane = new javax.swing.JScrollPane();
778  otherCasesTable = new javax.swing.JTable();
779  earliestCaseLabel = new javax.swing.JLabel();
780  earliestCaseDate = new javax.swing.JLabel();
781  tableStatusPanel = new javax.swing.JPanel();
782 
783  rightClickPopupMenu.addPopupMenuListener(new javax.swing.event.PopupMenuListener() {
784  public void popupMenuCanceled(javax.swing.event.PopupMenuEvent evt) {
785  }
786  public void popupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent evt) {
787  }
788  public void popupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent evt) {
789  rightClickPopupMenuPopupMenuWillBecomeVisible(evt);
790  }
791  });
792 
793  org.openide.awt.Mnemonics.setLocalizedText(selectAllMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.selectAllMenuItem.text")); // NOI18N
794  rightClickPopupMenu.add(selectAllMenuItem);
795 
796  org.openide.awt.Mnemonics.setLocalizedText(exportToCSVMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.exportToCSVMenuItem.text")); // NOI18N
797  rightClickPopupMenu.add(exportToCSVMenuItem);
798 
799  org.openide.awt.Mnemonics.setLocalizedText(showCaseDetailsMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.showCaseDetailsMenuItem.text")); // NOI18N
800  rightClickPopupMenu.add(showCaseDetailsMenuItem);
801 
802  org.openide.awt.Mnemonics.setLocalizedText(showCommonalityMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.showCommonalityMenuItem.text")); // NOI18N
803  rightClickPopupMenu.add(showCommonalityMenuItem);
804 
805  setMinimumSize(new java.awt.Dimension(1500, 10));
806  setOpaque(false);
807  setPreferredSize(new java.awt.Dimension(1500, 44));
808 
809  otherCasesPanel.setPreferredSize(new java.awt.Dimension(1500, 144));
810 
811  tableContainerPanel.setPreferredSize(new java.awt.Dimension(1500, 63));
812 
813  tableScrollPane.setPreferredSize(new java.awt.Dimension(1500, 30));
814 
815  otherCasesTable.setAutoCreateRowSorter(true);
816  otherCasesTable.setModel(tableModel);
817  otherCasesTable.setToolTipText(org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.table.toolTip.text")); // NOI18N
818  otherCasesTable.setComponentPopupMenu(rightClickPopupMenu);
819  otherCasesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_INTERVAL_SELECTION);
820  tableScrollPane.setViewportView(otherCasesTable);
821 
822  org.openide.awt.Mnemonics.setLocalizedText(earliestCaseLabel, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.earliestCaseLabel.text")); // NOI18N
823  earliestCaseLabel.setToolTipText(org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.earliestCaseLabel.toolTipText")); // NOI18N
824 
825  org.openide.awt.Mnemonics.setLocalizedText(earliestCaseDate, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.earliestCaseDate.text")); // NOI18N
826 
827  tableStatusPanel.setPreferredSize(new java.awt.Dimension(1500, 16));
828 
829  javax.swing.GroupLayout tableStatusPanelLayout = new javax.swing.GroupLayout(tableStatusPanel);
830  tableStatusPanel.setLayout(tableStatusPanelLayout);
831  tableStatusPanelLayout.setHorizontalGroup(
832  tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
833  .addGap(0, 0, Short.MAX_VALUE)
834  );
835  tableStatusPanelLayout.setVerticalGroup(
836  tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
837  .addGap(0, 16, Short.MAX_VALUE)
838  );
839 
840  javax.swing.GroupLayout tableContainerPanelLayout = new javax.swing.GroupLayout(tableContainerPanel);
841  tableContainerPanel.setLayout(tableContainerPanelLayout);
842  tableContainerPanelLayout.setHorizontalGroup(
843  tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
844  .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, tableContainerPanelLayout.createSequentialGroup()
845  .addComponent(tableStatusPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 1282, Short.MAX_VALUE)
846  .addGap(218, 218, 218))
847  .addComponent(tableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
848  .addGroup(tableContainerPanelLayout.createSequentialGroup()
849  .addComponent(earliestCaseLabel)
850  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
851  .addComponent(earliestCaseDate)
852  .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
853  );
854  tableContainerPanelLayout.setVerticalGroup(
855  tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
856  .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, tableContainerPanelLayout.createSequentialGroup()
857  .addComponent(tableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 27, Short.MAX_VALUE)
858  .addGap(2, 2, 2)
859  .addGroup(tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
860  .addComponent(earliestCaseLabel)
861  .addComponent(earliestCaseDate))
862  .addGap(0, 0, 0)
863  .addComponent(tableStatusPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
864  .addGap(0, 0, 0))
865  );
866 
867  javax.swing.GroupLayout otherCasesPanelLayout = new javax.swing.GroupLayout(otherCasesPanel);
868  otherCasesPanel.setLayout(otherCasesPanelLayout);
869  otherCasesPanelLayout.setHorizontalGroup(
870  otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
871  .addGap(0, 1500, Short.MAX_VALUE)
872  .addGroup(otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
873  .addComponent(tableContainerPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
874  );
875  otherCasesPanelLayout.setVerticalGroup(
876  otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
877  .addGap(0, 483, Short.MAX_VALUE)
878  .addGroup(otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
879  .addGroup(otherCasesPanelLayout.createSequentialGroup()
880  .addComponent(tableContainerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 59, Short.MAX_VALUE)
881  .addGap(0, 0, 0)))
882  );
883 
884  javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
885  this.setLayout(layout);
886  layout.setHorizontalGroup(
887  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
888  .addComponent(otherCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
889  );
890  layout.setVerticalGroup(
891  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
892  .addComponent(otherCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 59, Short.MAX_VALUE)
893  );
894  }// </editor-fold>//GEN-END:initComponents
895 
896  private void rightClickPopupMenuPopupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent evt) {//GEN-FIRST:event_rightClickPopupMenuPopupMenuWillBecomeVisible
897  boolean enableCentralRepoActions = false;
898 
899  if (EamDbUtil.useCentralRepo() && otherCasesTable.getSelectedRowCount() == 1) {
900  int rowIndex = otherCasesTable.getSelectedRow();
901  OtherOccurrenceNodeData selectedNode = (OtherOccurrenceNodeData) tableModel.getRow(rowIndex);
902  if (selectedNode instanceof OtherOccurrenceNodeInstanceData) {
903  OtherOccurrenceNodeInstanceData instanceData = (OtherOccurrenceNodeInstanceData) selectedNode;
904  enableCentralRepoActions = instanceData.isCentralRepoNode();
905  }
906  }
907  showCaseDetailsMenuItem.setVisible(enableCentralRepoActions);
908  showCommonalityMenuItem.setVisible(enableCentralRepoActions);
909  }//GEN-LAST:event_rightClickPopupMenuPopupMenuWillBecomeVisible
910 
911  // Variables declaration - do not modify//GEN-BEGIN:variables
912  private javax.swing.JFileChooser CSVFileChooser;
913  private javax.swing.JLabel earliestCaseDate;
914  private javax.swing.JLabel earliestCaseLabel;
915  private javax.swing.JMenuItem exportToCSVMenuItem;
916  private javax.swing.JPanel otherCasesPanel;
917  private javax.swing.JTable otherCasesTable;
918  private javax.swing.JPopupMenu rightClickPopupMenu;
919  private javax.swing.JMenuItem selectAllMenuItem;
920  private javax.swing.JMenuItem showCaseDetailsMenuItem;
921  private javax.swing.JMenuItem showCommonalityMenuItem;
922  private javax.swing.JPanel tableContainerPanel;
923  private javax.swing.JScrollPane tableScrollPane;
924  private javax.swing.JPanel tableStatusPanel;
925  // End of variables declaration//GEN-END:variables
926 
931  private static final class UniquePathKey {
932 
933  private final String dataSourceID;
934  private final String filePath;
935  private final String type;
936 
937  UniquePathKey(OtherOccurrenceNodeInstanceData nodeData) {
938  super();
939  dataSourceID = nodeData.getDeviceID();
940  if (nodeData.getFilePath() != null) {
941  filePath = nodeData.getFilePath().toLowerCase();
942  } else {
943  filePath = null;
944  }
945  type = nodeData.getType();
946  }
947 
948  @Override
949  public boolean equals(Object other) {
950  if (other instanceof UniquePathKey) {
951  UniquePathKey otherKey = (UniquePathKey) (other);
952  return (Objects.equals(otherKey.getDataSourceID(), this.getDataSourceID())
953  && Objects.equals(otherKey.getFilePath(), this.getFilePath())
954  && Objects.equals(otherKey.getType(), this.getType()));
955  }
956  return false;
957  }
958 
959  @Override
960  public int hashCode() {
961  //int hash = 7;
962  //hash = 67 * hash + this.dataSourceID.hashCode();
963  //hash = 67 * hash + this.filePath.hashCode();
964  return Objects.hash(getDataSourceID(), getFilePath(), getType());
965  }
966 
972  String getType() {
973  return type;
974  }
975 
981  String getFilePath() {
982  return filePath;
983  }
984 
990  String getDataSourceID() {
991  return dataSourceID;
992  }
993  }
994 }
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()
static List< CorrelationAttributeInstance > makeInstancesFromBlackboardArtifact(BlackboardArtifact bbArtifact, boolean checkEnabled)
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: Thu Oct 4 2018
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.