19 package org.sleuthkit.autopsy.centralrepository.contentviewer;
21 import java.awt.Component;
22 import java.awt.event.ActionEvent;
23 import java.awt.event.ActionListener;
24 import java.io.BufferedWriter;
26 import java.io.IOException;
27 import java.nio.file.Files;
28 import java.util.ArrayList;
29 import java.util.Calendar;
30 import java.util.Collection;
31 import java.util.Collections;
32 import java.util.List;
33 import java.util.logging.Level;
35 import java.util.stream.Collectors;
36 import javax.swing.JFileChooser;
37 import javax.swing.JMenuItem;
38 import javax.swing.JOptionPane;
39 import static javax.swing.JOptionPane.DEFAULT_OPTION;
40 import static javax.swing.JOptionPane.PLAIN_MESSAGE;
41 import static javax.swing.JOptionPane.ERROR_MESSAGE;
42 import javax.swing.filechooser.FileNameExtensionFilter;
43 import javax.swing.table.TableCellRenderer;
44 import javax.swing.table.TableColumn;
45 import org.openide.nodes.Node;
46 import org.openide.util.NbBundle.Messages;
47 import org.openide.util.lookup.ServiceProvider;
69 @Messages({
"DataContentViewerOtherCases.title=Other Occurrences",
70 "DataContentViewerOtherCases.toolTip=Displays instances of the selected file/artifact from other occurrences.",})
83 this.correlationAttributes =
new ArrayList<>();
86 customizeComponents();
91 ActionListener actList =
new ActionListener() {
93 public void actionPerformed(ActionEvent e) {
94 JMenuItem jmi = (JMenuItem) e.getSource();
95 if (jmi.equals(selectAllMenuItem)) {
96 otherCasesTable.selectAll();
97 }
else if (jmi.equals(showCaseDetailsMenuItem)) {
98 showCaseDetails(otherCasesTable.getSelectedRow());
99 }
else if (jmi.equals(exportToCSVMenuItem)) {
101 }
else if (jmi.equals(showCommonalityMenuItem)) {
102 showCommonalityDetails();
107 exportToCSVMenuItem.addActionListener(actList);
108 selectAllMenuItem.addActionListener(actList);
109 showCaseDetailsMenuItem.addActionListener(actList);
110 showCommonalityMenuItem.addActionListener(actList);
114 otherCasesTable.setDefaultRenderer(Object.class, renderer);
115 tableStatusPanelLabel.setVisible(
false);
118 @Messages({
"DataContentViewerOtherCases.correlatedArtifacts.isEmpty=There are no files or artifacts to correlate.",
119 "# {0} - commonality percentage",
120 "# {1} - correlation type",
121 "# {2} - correlation value",
122 "DataContentViewerOtherCases.correlatedArtifacts.byType={0}% of data sources have {2} (type: {1})\n",
123 "DataContentViewerOtherCases.correlatedArtifacts.title=Attribute Frequency",
124 "DataContentViewerOtherCases.correlatedArtifacts.failed=Failed to get frequency details."})
129 if (correlationAttributes.isEmpty()) {
130 JOptionPane.showConfirmDialog(showCommonalityMenuItem,
131 Bundle.DataContentViewerOtherCases_correlatedArtifacts_isEmpty(),
132 Bundle.DataContentViewerOtherCases_correlatedArtifacts_title(),
133 DEFAULT_OPTION, PLAIN_MESSAGE);
135 StringBuilder msg =
new StringBuilder();
141 msg.append(Bundle.DataContentViewerOtherCases_correlatedArtifacts_byType(percentage,
142 eamArtifact.getCorrelationType().getDisplayName(),
143 eamArtifact.getCorrelationValue()));
145 JOptionPane.showConfirmDialog(showCommonalityMenuItem,
147 Bundle.DataContentViewerOtherCases_correlatedArtifacts_title(),
148 DEFAULT_OPTION, PLAIN_MESSAGE);
150 LOGGER.log(Level.SEVERE,
"Error getting commonality details.", ex);
151 JOptionPane.showConfirmDialog(showCommonalityMenuItem,
152 Bundle.DataContentViewerOtherCases_correlatedArtifacts_failed(),
153 Bundle.DataContentViewerOtherCases_correlatedArtifacts_title(),
154 DEFAULT_OPTION, ERROR_MESSAGE);
159 @Messages({
"DataContentViewerOtherCases.caseDetailsDialog.notSelected=No Row Selected",
160 "DataContentViewerOtherCases.caseDetailsDialog.noDetails=No details for this case.",
161 "DataContentViewerOtherCases.caseDetailsDialog.noDetailsReference=No case details for Global reference properties.",
162 "DataContentViewerOtherCases.caseDetailsDialog.noCaseNameError=Error"})
164 String caseDisplayName = Bundle.DataContentViewerOtherCases_caseDetailsDialog_noCaseNameError();
166 if (-1 != selectedRowViewIdx) {
168 int selectedRowModelIdx = otherCasesTable.convertRowIndexToModel(selectedRowViewIdx);
171 if (eamCasePartial == null) {
172 JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
173 Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetailsReference(),
175 DEFAULT_OPTION, PLAIN_MESSAGE);
181 if (eamCase == null) {
182 JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
183 Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetails(),
185 DEFAULT_OPTION, PLAIN_MESSAGE);
190 JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
193 DEFAULT_OPTION, PLAIN_MESSAGE);
195 JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
196 Bundle.DataContentViewerOtherCases_caseDetailsDialog_notSelected(),
198 DEFAULT_OPTION, PLAIN_MESSAGE);
201 JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
202 Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetails(),
204 DEFAULT_OPTION, PLAIN_MESSAGE);
209 if (0 != otherCasesTable.getSelectedRowCount()) {
210 Calendar now = Calendar.getInstance();
211 String fileName = String.format(
"%1$tY%1$tm%1$te%1$tI%1$tM%1$tS_other_data_sources.csv", now);
213 CSVFileChooser.setSelectedFile(
new File(fileName));
214 CSVFileChooser.setFileFilter(
new FileNameExtensionFilter(
"csv file",
"csv"));
216 int returnVal = CSVFileChooser.showSaveDialog(otherCasesTable);
217 if (returnVal == JFileChooser.APPROVE_OPTION) {
219 File selectedFile = CSVFileChooser.getSelectedFile();
220 if (!selectedFile.getName().endsWith(
".csv")) {
221 selectedFile =
new File(selectedFile.toString() +
".csv");
224 writeSelectedRowsToFileAsCSV(selectedFile);
230 StringBuilder content;
231 int[] selectedRowViewIndices = otherCasesTable.getSelectedRows();
234 try (BufferedWriter writer = Files.newBufferedWriter(destFile.toPath())) {
237 content =
new StringBuilder(
"");
238 for (
int colIdx = 0; colIdx < colCount; colIdx++) {
239 content.append(
'"').append(tableModel.
getColumnName(colIdx)).append(
'"');
240 if (colIdx < (colCount - 1)) {
245 content.append(System.getProperty(
"line.separator"));
246 writer.write(content.toString());
249 for (
int rowViewIdx : selectedRowViewIndices) {
250 content =
new StringBuilder(
"");
251 for (
int colIdx = 0; colIdx < colCount; colIdx++) {
252 int rowModelIdx = otherCasesTable.convertRowIndexToModel(rowViewIdx);
253 content.append(
'"').append(tableModel.
getValueAt(rowModelIdx, colIdx)).append(
'"');
254 if (colIdx < (colCount - 1)) {
258 content.append(System.getProperty(
"line.separator"));
259 writer.write(content.toString());
262 }
catch (IOException ex) {
263 LOGGER.log(Level.SEVERE,
"Error writing selected rows to CSV.", ex);
273 correlationAttributes.clear();
278 return Bundle.DataContentViewerOtherCases_title();
283 return Bundle.DataContentViewerOtherCases_toolTip();
314 BlackboardArtifactTag nodeBbArtifactTag = node.getLookup().lookup(BlackboardArtifactTag.class);
315 BlackboardArtifact nodeBbArtifact = node.getLookup().lookup(BlackboardArtifact.class);
317 if (nodeBbArtifactTag != null) {
318 return nodeBbArtifactTag.getArtifact();
319 }
else if (nodeBbArtifact != null) {
320 return nodeBbArtifact;
334 BlackboardArtifactTag nodeBbArtifactTag = node.getLookup().lookup(BlackboardArtifactTag.class);
335 ContentTag nodeContentTag = node.getLookup().lookup(ContentTag.class);
336 BlackboardArtifact nodeBbArtifact = node.getLookup().lookup(BlackboardArtifact.class);
337 AbstractFile nodeAbstractFile = node.getLookup().lookup(AbstractFile.class);
339 if (nodeBbArtifactTag != null) {
340 Content content = nodeBbArtifactTag.getContent();
341 if (content instanceof AbstractFile) {
342 return (AbstractFile) content;
344 }
else if (nodeContentTag != null) {
345 Content content = nodeContentTag.getContent();
346 if (content instanceof AbstractFile) {
347 return (AbstractFile) content;
349 }
else if (nodeBbArtifact != null) {
352 content = nodeBbArtifact.getSleuthkitCase().getContentById(nodeBbArtifact.getObjectID());
353 }
catch (TskCoreException ex) {
354 LOGGER.log(Level.SEVERE,
"Error retrieving blackboard artifact", ex);
358 if (content instanceof AbstractFile) {
359 return (AbstractFile) content;
361 }
else if (nodeAbstractFile != null) {
362 return nodeAbstractFile;
376 Collection<CorrelationAttribute> ret =
new ArrayList<>();
379 BlackboardArtifact bbArtifact = getBlackboardArtifactFromNode(node);
380 if (bbArtifact != null) {
385 AbstractFile abstractFile = getAbstractFileFromNode(node);
386 if (abstractFile != null) {
389 String md5 = abstractFile.getMd5Hash();
390 if (md5 != null && !md5.isEmpty() && null != artifactTypes && !artifactTypes.isEmpty()) {
399 LOGGER.log(Level.SEVERE,
"Error connecting to DB", ex);
424 .filter(artifactInstance -> !artifactInstance.getCorrelationCase().getCaseUUID().equals(caseUUID)
425 || !artifactInstance.getCorrelationDataSource().getName().equals(dataSourceName)
426 || !artifactInstance.getCorrelationDataSource().getDeviceID().equals(deviceId))
427 .collect(Collectors.toList());
428 return artifactInstances;
430 LOGGER.log(Level.SEVERE,
"Error getting artifact instances from database.", ex);
433 return Collections.emptyList();
446 Collection<CorrelationAttributeInstance> eamArtifactInstances =
new ArrayList<>();
449 return Collections.emptyList();
454 eamGlobalFileInstances.forEach((eamGlobalFileInstance) -> {
459 return eamArtifactInstances;
461 LOGGER.log(Level.SEVERE,
"Error getting reference instances from database.", ex);
463 return Collections.emptyList();
473 return !getCorrelationAttributesFromNode(node).isEmpty();
477 @Messages({
"DataContentViewerOtherCases.table.nodbconnection=Cannot connect to central repository database."})
496 @Messages({
"DataContentViewerOtherCases.table.isempty=There are no associated artifacts or files from other occurrences to display.",
497 "DataContentViewerOtherCases.table.noArtifacts=Correlation cannot be performed on the selected file."})
499 AbstractFile af = getAbstractFileFromNode(node);
500 String dataSourceName =
"";
501 String deviceId =
"";
504 Content dataSource = af.getDataSource();
505 dataSourceName = dataSource.getName();
508 }
catch (TskException ex) {
514 correlationAttributes.addAll(getCorrelationAttributesFromNode(node));
516 Collection<CorrelationAttributeInstance> corAttrInstances =
new ArrayList<>();
519 corAttrInstances.addAll(getCorrelatedInstances(corAttr, dataSourceName, deviceId));
520 corAttrInstances.addAll(getReferenceInstancesAsArtifactInstances(corAttr));
522 corAttrInstances.forEach((corAttrInstance) -> {
524 corAttr.getCorrelationType(),
525 corAttr.getCorrelationValue()
532 if (correlationAttributes.isEmpty()) {
533 displayMessageOnTableStatusPanel(Bundle.DataContentViewerOtherCases_table_noArtifacts());
535 displayMessageOnTableStatusPanel(Bundle.DataContentViewerOtherCases_table_isempty());
537 clearMessageOnTableStatusPanel();
544 TableColumn column = otherCasesTable.getColumnModel().getColumn(idx);
547 column.setPreferredWidth(colWidth);
553 tableStatusPanelLabel.setText(message);
554 tableStatusPanelLabel.setVisible(
true);
558 tableStatusPanelLabel.setVisible(
false);
566 @SuppressWarnings(
"unchecked")
568 private
void initComponents() {
570 rightClickPopupMenu =
new javax.swing.JPopupMenu();
571 selectAllMenuItem =
new javax.swing.JMenuItem();
572 exportToCSVMenuItem =
new javax.swing.JMenuItem();
573 showCaseDetailsMenuItem =
new javax.swing.JMenuItem();
574 showCommonalityMenuItem =
new javax.swing.JMenuItem();
575 CSVFileChooser =
new javax.swing.JFileChooser();
576 otherCasesPanel =
new javax.swing.JPanel();
577 tableContainerPanel =
new javax.swing.JPanel();
578 tableScrollPane =
new javax.swing.JScrollPane();
579 otherCasesTable =
new javax.swing.JTable();
580 tableStatusPanel =
new javax.swing.JPanel();
581 tableStatusPanelLabel =
new javax.swing.JLabel();
583 org.openide.awt.Mnemonics.setLocalizedText(selectAllMenuItem,
org.openide.util.NbBundle.getMessage(
DataContentViewerOtherCases.class,
"DataContentViewerOtherCases.selectAllMenuItem.text"));
584 rightClickPopupMenu.add(selectAllMenuItem);
586 org.openide.awt.Mnemonics.setLocalizedText(exportToCSVMenuItem,
org.openide.util.NbBundle.getMessage(
DataContentViewerOtherCases.class,
"DataContentViewerOtherCases.exportToCSVMenuItem.text"));
587 rightClickPopupMenu.add(exportToCSVMenuItem);
589 org.openide.awt.Mnemonics.setLocalizedText(showCaseDetailsMenuItem,
org.openide.util.NbBundle.getMessage(
DataContentViewerOtherCases.class,
"DataContentViewerOtherCases.showCaseDetailsMenuItem.text"));
590 rightClickPopupMenu.add(showCaseDetailsMenuItem);
592 org.openide.awt.Mnemonics.setLocalizedText(showCommonalityMenuItem,
org.openide.util.NbBundle.getMessage(
DataContentViewerOtherCases.class,
"DataContentViewerOtherCases.showCommonalityMenuItem.text"));
593 rightClickPopupMenu.add(showCommonalityMenuItem);
595 tableScrollPane.setPreferredSize(
new java.awt.Dimension(452, 30));
597 otherCasesTable.setAutoCreateRowSorter(
true);
598 otherCasesTable.setModel(tableModel);
599 otherCasesTable.setToolTipText(
org.openide.util.NbBundle.getMessage(
DataContentViewerOtherCases.class,
"DataContentViewerOtherCases.table.toolTip.text"));
600 otherCasesTable.setComponentPopupMenu(rightClickPopupMenu);
601 otherCasesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_INTERVAL_SELECTION);
602 tableScrollPane.setViewportView(otherCasesTable);
604 tableStatusPanelLabel.setForeground(
new java.awt.Color(255, 0, 51));
606 javax.swing.GroupLayout tableStatusPanelLayout =
new javax.swing.GroupLayout(tableStatusPanel);
607 tableStatusPanel.setLayout(tableStatusPanelLayout);
608 tableStatusPanelLayout.setHorizontalGroup(
609 tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
610 .addGap(0, 0, Short.MAX_VALUE)
611 .addGroup(tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
612 .addGroup(tableStatusPanelLayout.createSequentialGroup()
614 .addComponent(tableStatusPanelLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 780, Short.MAX_VALUE)
617 tableStatusPanelLayout.setVerticalGroup(
618 tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
619 .addGap(0, 16, Short.MAX_VALUE)
620 .addGroup(tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
621 .addGroup(tableStatusPanelLayout.createSequentialGroup()
622 .addComponent(tableStatusPanelLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE)
623 .addGap(0, 0, Short.MAX_VALUE)))
626 javax.swing.GroupLayout tableContainerPanelLayout =
new javax.swing.GroupLayout(tableContainerPanel);
627 tableContainerPanel.setLayout(tableContainerPanelLayout);
628 tableContainerPanelLayout.setHorizontalGroup(
629 tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
630 .addComponent(tableScrollPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
631 .addComponent(tableStatusPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
633 tableContainerPanelLayout.setVerticalGroup(
634 tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
635 .addGroup(tableContainerPanelLayout.createSequentialGroup()
636 .addComponent(tableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
637 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
638 .addComponent(tableStatusPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
642 javax.swing.GroupLayout otherCasesPanelLayout =
new javax.swing.GroupLayout(otherCasesPanel);
643 otherCasesPanel.setLayout(otherCasesPanelLayout);
644 otherCasesPanelLayout.setHorizontalGroup(
645 otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
646 .addGap(0, 800, Short.MAX_VALUE)
647 .addGroup(otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
648 .addComponent(tableContainerPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
650 otherCasesPanelLayout.setVerticalGroup(
651 otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
652 .addGap(0, 144, Short.MAX_VALUE)
653 .addGroup(otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
654 .addGroup(otherCasesPanelLayout.createSequentialGroup()
655 .addComponent(tableContainerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
659 javax.swing.GroupLayout layout =
new javax.swing.GroupLayout(
this);
660 this.setLayout(layout);
661 layout.setHorizontalGroup(
662 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
663 .addComponent(otherCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
665 layout.setVerticalGroup(
666 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
667 .addComponent(otherCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
int getFrequencyPercentage(CorrelationAttribute corAttr)
String getCorrelationValue()
void writeSelectedRowsToFileAsCSV(File destFile)
final DataContentViewerOtherCasesTableModel tableModel
CorrelationCase getCaseByUUID(String caseUUID)
javax.swing.JScrollPane tableScrollPane
int isPreferred(Node node)
javax.swing.JMenuItem selectAllMenuItem
Type getCorrelationType()
static final int FILES_TYPE_ID
javax.swing.JMenuItem showCommonalityMenuItem
final Collection< CorrelationAttribute > correlationAttributes
javax.swing.JPanel tableContainerPanel
AbstractFile getAbstractFileFromNode(Node node)
javax.swing.JLabel tableStatusPanelLabel
void addInstance(CorrelationAttributeInstance artifactInstance)
List< CorrelationAttributeInstance > getArtifactInstancesByTypeValue(CorrelationAttribute.Type aType, String value)
javax.swing.JPanel otherCasesPanel
void populateTable(Node node)
javax.swing.JPopupMenu rightClickPopupMenu
BlackboardArtifact getBlackboardArtifactFromNode(Node node)
static EamDb getInstance()
boolean isSupported(Node node)
Collection< CorrelationAttribute > getCorrelationAttributesFromNode(Node node)
int getColumnPreferredWidth(int colIdx)
String getCaseDetailsOptionsPaneDialog()
javax.swing.JTable otherCasesTable
void showCaseDetails(int selectedRowViewIdx)
String getColumnName(int colIdx)
javax.swing.JMenuItem exportToCSVMenuItem
List< CorrelationAttributeInstance > getInstances()
static boolean isEnabled()
SleuthkitCase getSleuthkitCase()
void showCommonalityDetails()
List< EamGlobalFileInstance > getReferenceInstancesByTypeValue(CorrelationAttribute.Type aType, String aValue)
Object getValueAt(int rowIdx, int colIdx)
DataContentViewerOtherCases()
Object getRow(int rowIdx)
void addEamArtifact(CorrelationAttribute eamArtifact)
javax.swing.JPanel tableStatusPanel
javax.swing.JFileChooser CSVFileChooser
void clearMessageOnTableStatusPanel()
static Case getCurrentCase()
synchronized static Logger getLogger(String name)
void displayMessageOnTableStatusPanel(String message)
Collection< CorrelationAttributeInstance > getCorrelatedInstances(CorrelationAttribute corAttr, String dataSourceName, String deviceId)
Collection< CorrelationAttributeInstance > getReferenceInstancesAsArtifactInstances(CorrelationAttribute eamArtifact)
String getExportDirectory()
DataContentViewer createInstance()
List< CorrelationAttribute.Type > getDefinedCorrelationTypes()
void customizeComponents()
static List< CorrelationAttribute > getCorrelationAttributeFromBlackboardArtifact(BlackboardArtifact bbArtifact, boolean addInstanceDetails, boolean checkEnabled)
javax.swing.JMenuItem showCaseDetailsMenuItem