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;
70 @Messages({
"DataContentViewerOtherCases.title=Other Occurrences",
71 "DataContentViewerOtherCases.toolTip=Displays instances of the selected file/artifact from other occurrences.",})
84 this.correlationAttributes =
new ArrayList<>();
87 customizeComponents();
92 ActionListener actList =
new ActionListener() {
94 public void actionPerformed(ActionEvent e) {
95 JMenuItem jmi = (JMenuItem) e.getSource();
96 if (jmi.equals(selectAllMenuItem)) {
97 otherCasesTable.selectAll();
98 }
else if (jmi.equals(showCaseDetailsMenuItem)) {
99 showCaseDetails(otherCasesTable.getSelectedRow());
100 }
else if (jmi.equals(exportToCSVMenuItem)) {
104 LOGGER.log(Level.SEVERE,
"Exception while getting open case.", ex);
106 }
else if (jmi.equals(showCommonalityMenuItem)) {
107 showCommonalityDetails();
112 exportToCSVMenuItem.addActionListener(actList);
113 selectAllMenuItem.addActionListener(actList);
114 showCaseDetailsMenuItem.addActionListener(actList);
115 showCommonalityMenuItem.addActionListener(actList);
119 otherCasesTable.setDefaultRenderer(Object.class, renderer);
120 tableStatusPanelLabel.setVisible(
false);
123 @Messages({
"DataContentViewerOtherCases.correlatedArtifacts.isEmpty=There are no files or artifacts to correlate.",
124 "# {0} - commonality percentage",
125 "# {1} - correlation type",
126 "# {2} - correlation value",
127 "DataContentViewerOtherCases.correlatedArtifacts.byType={0}% of data sources have {2} (type: {1})\n",
128 "DataContentViewerOtherCases.correlatedArtifacts.title=Attribute Frequency",
129 "DataContentViewerOtherCases.correlatedArtifacts.failed=Failed to get frequency details."})
134 if (correlationAttributes.isEmpty()) {
135 JOptionPane.showConfirmDialog(showCommonalityMenuItem,
136 Bundle.DataContentViewerOtherCases_correlatedArtifacts_isEmpty(),
137 Bundle.DataContentViewerOtherCases_correlatedArtifacts_title(),
138 DEFAULT_OPTION, PLAIN_MESSAGE);
140 StringBuilder msg =
new StringBuilder();
146 msg.append(Bundle.DataContentViewerOtherCases_correlatedArtifacts_byType(percentage,
147 eamArtifact.getCorrelationType().getDisplayName(),
148 eamArtifact.getCorrelationValue()));
150 JOptionPane.showConfirmDialog(showCommonalityMenuItem,
152 Bundle.DataContentViewerOtherCases_correlatedArtifacts_title(),
153 DEFAULT_OPTION, PLAIN_MESSAGE);
155 LOGGER.log(Level.SEVERE,
"Error getting commonality details.", ex);
156 JOptionPane.showConfirmDialog(showCommonalityMenuItem,
157 Bundle.DataContentViewerOtherCases_correlatedArtifacts_failed(),
158 Bundle.DataContentViewerOtherCases_correlatedArtifacts_title(),
159 DEFAULT_OPTION, ERROR_MESSAGE);
164 @Messages({
"DataContentViewerOtherCases.caseDetailsDialog.notSelected=No Row Selected",
165 "DataContentViewerOtherCases.caseDetailsDialog.noDetails=No details for this case.",
166 "DataContentViewerOtherCases.caseDetailsDialog.noDetailsReference=No case details for Global reference properties.",
167 "DataContentViewerOtherCases.caseDetailsDialog.noCaseNameError=Error",
168 "DataContentViewerOtherCases.noOpenCase.errMsg=No open case available."})
174 JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
175 Bundle.DataContentViewerOtherCases_noOpenCase_errMsg(),
176 Bundle.DataContentViewerOtherCases_noOpenCase_errMsg(),
177 DEFAULT_OPTION, PLAIN_MESSAGE);
180 String caseDisplayName = Bundle.DataContentViewerOtherCases_caseDetailsDialog_noCaseNameError();
182 if (-1 != selectedRowViewIdx) {
184 int selectedRowModelIdx = otherCasesTable.convertRowIndexToModel(selectedRowViewIdx);
187 if (eamCasePartial == null) {
188 JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
189 Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetailsReference(),
191 DEFAULT_OPTION, PLAIN_MESSAGE);
197 if (eamCase == null) {
198 JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
199 Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetails(),
201 DEFAULT_OPTION, PLAIN_MESSAGE);
206 JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
209 DEFAULT_OPTION, PLAIN_MESSAGE);
211 JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
212 Bundle.DataContentViewerOtherCases_caseDetailsDialog_notSelected(),
214 DEFAULT_OPTION, PLAIN_MESSAGE);
217 JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
218 Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetails(),
220 DEFAULT_OPTION, PLAIN_MESSAGE);
225 if (0 != otherCasesTable.getSelectedRowCount()) {
226 Calendar now = Calendar.getInstance();
227 String fileName = String.format(
"%1$tY%1$tm%1$te%1$tI%1$tM%1$tS_other_data_sources.csv", now);
229 CSVFileChooser.setSelectedFile(
new File(fileName));
230 CSVFileChooser.setFileFilter(
new FileNameExtensionFilter(
"csv file",
"csv"));
232 int returnVal = CSVFileChooser.showSaveDialog(otherCasesTable);
233 if (returnVal == JFileChooser.APPROVE_OPTION) {
235 File selectedFile = CSVFileChooser.getSelectedFile();
236 if (!selectedFile.getName().endsWith(
".csv")) {
237 selectedFile =
new File(selectedFile.toString() +
".csv");
240 writeSelectedRowsToFileAsCSV(selectedFile);
246 StringBuilder content;
247 int[] selectedRowViewIndices = otherCasesTable.getSelectedRows();
250 try (BufferedWriter writer = Files.newBufferedWriter(destFile.toPath())) {
253 content =
new StringBuilder(
"");
254 for (
int colIdx = 0; colIdx < colCount; colIdx++) {
255 content.append(
'"').append(tableModel.
getColumnName(colIdx)).append(
'"');
256 if (colIdx < (colCount - 1)) {
261 content.append(System.getProperty(
"line.separator"));
262 writer.write(content.toString());
265 for (
int rowViewIdx : selectedRowViewIndices) {
266 content =
new StringBuilder(
"");
267 for (
int colIdx = 0; colIdx < colCount; colIdx++) {
268 int rowModelIdx = otherCasesTable.convertRowIndexToModel(rowViewIdx);
269 content.append(
'"').append(tableModel.
getValueAt(rowModelIdx, colIdx)).append(
'"');
270 if (colIdx < (colCount - 1)) {
274 content.append(System.getProperty(
"line.separator"));
275 writer.write(content.toString());
278 }
catch (IOException ex) {
279 LOGGER.log(Level.SEVERE,
"Error writing selected rows to CSV.", ex);
289 correlationAttributes.clear();
294 return Bundle.DataContentViewerOtherCases_title();
299 return Bundle.DataContentViewerOtherCases_toolTip();
330 BlackboardArtifactTag nodeBbArtifactTag = node.getLookup().lookup(BlackboardArtifactTag.class);
331 BlackboardArtifact nodeBbArtifact = node.getLookup().lookup(BlackboardArtifact.class);
333 if (nodeBbArtifactTag != null) {
334 return nodeBbArtifactTag.getArtifact();
335 }
else if (nodeBbArtifact != null) {
336 return nodeBbArtifact;
350 BlackboardArtifactTag nodeBbArtifactTag = node.getLookup().lookup(BlackboardArtifactTag.class);
351 ContentTag nodeContentTag = node.getLookup().lookup(ContentTag.class);
352 BlackboardArtifact nodeBbArtifact = node.getLookup().lookup(BlackboardArtifact.class);
353 AbstractFile nodeAbstractFile = node.getLookup().lookup(AbstractFile.class);
355 if (nodeBbArtifactTag != null) {
356 Content content = nodeBbArtifactTag.getContent();
357 if (content instanceof AbstractFile) {
358 return (AbstractFile) content;
360 }
else if (nodeContentTag != null) {
361 Content content = nodeContentTag.getContent();
362 if (content instanceof AbstractFile) {
363 return (AbstractFile) content;
365 }
else if (nodeBbArtifact != null) {
368 content = nodeBbArtifact.getSleuthkitCase().getContentById(nodeBbArtifact.getObjectID());
369 }
catch (TskCoreException ex) {
370 LOGGER.log(Level.SEVERE,
"Error retrieving blackboard artifact", ex);
374 if (content instanceof AbstractFile) {
375 return (AbstractFile) content;
377 }
else if (nodeAbstractFile != null) {
378 return nodeAbstractFile;
392 Collection<CorrelationAttribute> ret =
new ArrayList<>();
395 BlackboardArtifact bbArtifact = getBlackboardArtifactFromNode(node);
396 if (bbArtifact != null) {
401 AbstractFile abstractFile = getAbstractFileFromNode(node);
402 if (abstractFile != null) {
405 String md5 = abstractFile.getMd5Hash();
406 if (md5 != null && !md5.isEmpty() && null != artifactTypes && !artifactTypes.isEmpty()) {
415 LOGGER.log(Level.SEVERE,
"Error connecting to DB", ex);
440 .filter(artifactInstance -> !artifactInstance.getCorrelationCase().getCaseUUID().equals(caseUUID)
441 || !artifactInstance.getCorrelationDataSource().getName().equals(dataSourceName)
442 || !artifactInstance.getCorrelationDataSource().getDeviceID().equals(deviceId))
443 .collect(Collectors.toList());
444 return artifactInstances;
446 LOGGER.log(Level.SEVERE,
"Error getting artifact instances from database.", ex);
448 LOGGER.log(Level.SEVERE,
"Exception while getting open case.", ex);
451 return Collections.emptyList();
461 return !getCorrelationAttributesFromNode(node).isEmpty();
465 @Messages({
"DataContentViewerOtherCases.table.nodbconnection=Cannot connect to central repository database."})
484 @Messages({
"DataContentViewerOtherCases.table.isempty=There are no associated artifacts or files from other occurrences to display.",
485 "DataContentViewerOtherCases.table.noArtifacts=Correlation cannot be performed on the selected file."})
487 AbstractFile af = getAbstractFileFromNode(node);
488 String dataSourceName =
"";
489 String deviceId =
"";
492 Content dataSource = af.getDataSource();
493 dataSourceName = dataSource.getName();
502 correlationAttributes.addAll(getCorrelationAttributesFromNode(node));
504 Collection<CorrelationAttributeInstance> corAttrInstances =
new ArrayList<>();
507 corAttrInstances.addAll(getCorrelatedInstances(corAttr, dataSourceName, deviceId));
509 corAttrInstances.forEach((corAttrInstance) -> {
512 corAttr.getCorrelationType(),
513 corAttr.getCorrelationValue()
518 LOGGER.log(Level.SEVERE,
"Error creating correlation attribute", ex);
523 if (correlationAttributes.isEmpty()) {
524 displayMessageOnTableStatusPanel(Bundle.DataContentViewerOtherCases_table_noArtifacts());
526 displayMessageOnTableStatusPanel(Bundle.DataContentViewerOtherCases_table_isempty());
528 clearMessageOnTableStatusPanel();
535 TableColumn column = otherCasesTable.getColumnModel().getColumn(idx);
538 column.setPreferredWidth(colWidth);
544 tableStatusPanelLabel.setText(message);
545 tableStatusPanelLabel.setVisible(
true);
549 tableStatusPanelLabel.setVisible(
false);
557 @SuppressWarnings(
"unchecked")
559 private
void initComponents() {
561 rightClickPopupMenu =
new javax.swing.JPopupMenu();
562 selectAllMenuItem =
new javax.swing.JMenuItem();
563 exportToCSVMenuItem =
new javax.swing.JMenuItem();
564 showCaseDetailsMenuItem =
new javax.swing.JMenuItem();
565 showCommonalityMenuItem =
new javax.swing.JMenuItem();
566 CSVFileChooser =
new javax.swing.JFileChooser();
567 otherCasesPanel =
new javax.swing.JPanel();
568 tableContainerPanel =
new javax.swing.JPanel();
569 tableScrollPane =
new javax.swing.JScrollPane();
570 otherCasesTable =
new javax.swing.JTable();
571 tableStatusPanel =
new javax.swing.JPanel();
572 tableStatusPanelLabel =
new javax.swing.JLabel();
574 org.openide.awt.Mnemonics.setLocalizedText(selectAllMenuItem,
org.openide.util.NbBundle.getMessage(
DataContentViewerOtherCases.class,
"DataContentViewerOtherCases.selectAllMenuItem.text"));
575 rightClickPopupMenu.add(selectAllMenuItem);
577 org.openide.awt.Mnemonics.setLocalizedText(exportToCSVMenuItem,
org.openide.util.NbBundle.getMessage(
DataContentViewerOtherCases.class,
"DataContentViewerOtherCases.exportToCSVMenuItem.text"));
578 rightClickPopupMenu.add(exportToCSVMenuItem);
580 org.openide.awt.Mnemonics.setLocalizedText(showCaseDetailsMenuItem,
org.openide.util.NbBundle.getMessage(
DataContentViewerOtherCases.class,
"DataContentViewerOtherCases.showCaseDetailsMenuItem.text"));
581 rightClickPopupMenu.add(showCaseDetailsMenuItem);
583 org.openide.awt.Mnemonics.setLocalizedText(showCommonalityMenuItem,
org.openide.util.NbBundle.getMessage(
DataContentViewerOtherCases.class,
"DataContentViewerOtherCases.showCommonalityMenuItem.text"));
584 rightClickPopupMenu.add(showCommonalityMenuItem);
586 setMinimumSize(
new java.awt.Dimension(1500, 10));
588 setPreferredSize(
new java.awt.Dimension(1500, 44));
590 otherCasesPanel.setPreferredSize(
new java.awt.Dimension(1500, 144));
592 tableContainerPanel.setPreferredSize(
new java.awt.Dimension(1500, 63));
594 tableScrollPane.setPreferredSize(
new java.awt.Dimension(1500, 30));
596 otherCasesTable.setAutoCreateRowSorter(
true);
597 otherCasesTable.setModel(tableModel);
598 otherCasesTable.setToolTipText(
org.openide.util.NbBundle.getMessage(
DataContentViewerOtherCases.class,
"DataContentViewerOtherCases.table.toolTip.text"));
599 otherCasesTable.setComponentPopupMenu(rightClickPopupMenu);
600 otherCasesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_INTERVAL_SELECTION);
601 tableScrollPane.setViewportView(otherCasesTable);
603 tableStatusPanel.setPreferredSize(
new java.awt.Dimension(1500, 16));
605 tableStatusPanelLabel.setForeground(
new java.awt.Color(255, 0, 51));
607 javax.swing.GroupLayout tableStatusPanelLayout =
new javax.swing.GroupLayout(tableStatusPanel);
608 tableStatusPanel.setLayout(tableStatusPanelLayout);
609 tableStatusPanelLayout.setHorizontalGroup(
610 tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
611 .addGap(0, 0, Short.MAX_VALUE)
612 .addGroup(tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
613 .addGroup(tableStatusPanelLayout.createSequentialGroup()
615 .addComponent(tableStatusPanelLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 780, Short.MAX_VALUE)
618 tableStatusPanelLayout.setVerticalGroup(
619 tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
620 .addGap(0, 16, Short.MAX_VALUE)
621 .addGroup(tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
622 .addGroup(tableStatusPanelLayout.createSequentialGroup()
623 .addComponent(tableStatusPanelLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE)
624 .addGap(0, 0, Short.MAX_VALUE)))
627 javax.swing.GroupLayout tableContainerPanelLayout =
new javax.swing.GroupLayout(tableContainerPanel);
628 tableContainerPanel.setLayout(tableContainerPanelLayout);
629 tableContainerPanelLayout.setHorizontalGroup(
630 tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
631 .addComponent(tableScrollPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
632 .addComponent(tableStatusPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
634 tableContainerPanelLayout.setVerticalGroup(
635 tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
636 .addGroup(tableContainerPanelLayout.createSequentialGroup()
637 .addComponent(tableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
638 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
639 .addComponent(tableStatusPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
643 javax.swing.GroupLayout otherCasesPanelLayout =
new javax.swing.GroupLayout(otherCasesPanel);
644 otherCasesPanel.setLayout(otherCasesPanelLayout);
645 otherCasesPanelLayout.setHorizontalGroup(
646 otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
647 .addGap(0, 1500, Short.MAX_VALUE)
648 .addGroup(otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
649 .addComponent(tableContainerPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
651 otherCasesPanelLayout.setVerticalGroup(
652 otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
653 .addGap(0, 60, Short.MAX_VALUE)
654 .addGroup(otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
655 .addGroup(otherCasesPanelLayout.createSequentialGroup()
656 .addComponent(tableContainerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 60, Short.MAX_VALUE)
660 javax.swing.GroupLayout layout =
new javax.swing.GroupLayout(
this);
661 this.setLayout(layout);
662 layout.setHorizontalGroup(
663 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
664 .addComponent(otherCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
666 layout.setVerticalGroup(
667 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
668 .addComponent(otherCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 60, Short.MAX_VALUE)
int getFrequencyPercentage(CorrelationAttribute corAttr)
String getCorrelationValue()
void writeSelectedRowsToFileAsCSV(File destFile)
final DataContentViewerOtherCasesTableModel tableModel
javax.swing.JScrollPane tableScrollPane
int isPreferred(Node node)
javax.swing.JMenuItem selectAllMenuItem
Type getCorrelationType()
static final int FILES_TYPE_ID
javax.swing.JMenuItem showCommonalityMenuItem
static Case getOpenCase()
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()
Object getValueAt(int rowIdx, int colIdx)
DataContentViewerOtherCases()
Object getRow(int rowIdx)
void addEamArtifact(CorrelationAttribute eamArtifact)
javax.swing.JPanel tableStatusPanel
CorrelationCase getCase(Case autopsyCase)
javax.swing.JFileChooser CSVFileChooser
void clearMessageOnTableStatusPanel()
synchronized static Logger getLogger(String name)
void displayMessageOnTableStatusPanel(String message)
Collection< CorrelationAttributeInstance > getCorrelatedInstances(CorrelationAttribute corAttr, String dataSourceName, String deviceId)
String getExportDirectory()
DataContentViewer createInstance()
List< CorrelationAttribute.Type > getDefinedCorrelationTypes()
void customizeComponents()
static List< CorrelationAttribute > getCorrelationAttributeFromBlackboardArtifact(BlackboardArtifact bbArtifact, boolean addInstanceDetails, boolean checkEnabled)
javax.swing.JMenuItem showCaseDetailsMenuItem