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();
443 return !getCorrelationAttributesFromNode(node).isEmpty();
447 @Messages({
"DataContentViewerOtherCases.table.nodbconnection=Cannot connect to central repository database."})
466 @Messages({
"DataContentViewerOtherCases.table.isempty=There are no associated artifacts or files from other occurrences to display.",
467 "DataContentViewerOtherCases.table.noArtifacts=Correlation cannot be performed on the selected file."})
469 AbstractFile af = getAbstractFileFromNode(node);
470 String dataSourceName =
"";
471 String deviceId =
"";
474 Content dataSource = af.getDataSource();
475 dataSourceName = dataSource.getName();
478 }
catch (TskException ex) {
484 correlationAttributes.addAll(getCorrelationAttributesFromNode(node));
486 Collection<CorrelationAttributeInstance> corAttrInstances =
new ArrayList<>();
489 corAttrInstances.addAll(getCorrelatedInstances(corAttr, dataSourceName, deviceId));
491 corAttrInstances.forEach((corAttrInstance) -> {
494 corAttr.getCorrelationType(),
495 corAttr.getCorrelationValue()
500 LOGGER.log(Level.SEVERE,
"Error creating correlation attribute", ex);
505 if (correlationAttributes.isEmpty()) {
506 displayMessageOnTableStatusPanel(Bundle.DataContentViewerOtherCases_table_noArtifacts());
508 displayMessageOnTableStatusPanel(Bundle.DataContentViewerOtherCases_table_isempty());
510 clearMessageOnTableStatusPanel();
517 TableColumn column = otherCasesTable.getColumnModel().getColumn(idx);
520 column.setPreferredWidth(colWidth);
526 tableStatusPanelLabel.setText(message);
527 tableStatusPanelLabel.setVisible(
true);
531 tableStatusPanelLabel.setVisible(
false);
539 @SuppressWarnings(
"unchecked")
541 private
void initComponents() {
543 rightClickPopupMenu =
new javax.swing.JPopupMenu();
544 selectAllMenuItem =
new javax.swing.JMenuItem();
545 exportToCSVMenuItem =
new javax.swing.JMenuItem();
546 showCaseDetailsMenuItem =
new javax.swing.JMenuItem();
547 showCommonalityMenuItem =
new javax.swing.JMenuItem();
548 CSVFileChooser =
new javax.swing.JFileChooser();
549 otherCasesPanel =
new javax.swing.JPanel();
550 tableContainerPanel =
new javax.swing.JPanel();
551 tableScrollPane =
new javax.swing.JScrollPane();
552 otherCasesTable =
new javax.swing.JTable();
553 tableStatusPanel =
new javax.swing.JPanel();
554 tableStatusPanelLabel =
new javax.swing.JLabel();
556 org.openide.awt.Mnemonics.setLocalizedText(selectAllMenuItem,
org.openide.util.NbBundle.getMessage(
DataContentViewerOtherCases.class,
"DataContentViewerOtherCases.selectAllMenuItem.text"));
557 rightClickPopupMenu.add(selectAllMenuItem);
559 org.openide.awt.Mnemonics.setLocalizedText(exportToCSVMenuItem,
org.openide.util.NbBundle.getMessage(
DataContentViewerOtherCases.class,
"DataContentViewerOtherCases.exportToCSVMenuItem.text"));
560 rightClickPopupMenu.add(exportToCSVMenuItem);
562 org.openide.awt.Mnemonics.setLocalizedText(showCaseDetailsMenuItem,
org.openide.util.NbBundle.getMessage(
DataContentViewerOtherCases.class,
"DataContentViewerOtherCases.showCaseDetailsMenuItem.text"));
563 rightClickPopupMenu.add(showCaseDetailsMenuItem);
565 org.openide.awt.Mnemonics.setLocalizedText(showCommonalityMenuItem,
org.openide.util.NbBundle.getMessage(
DataContentViewerOtherCases.class,
"DataContentViewerOtherCases.showCommonalityMenuItem.text"));
566 rightClickPopupMenu.add(showCommonalityMenuItem);
568 setMinimumSize(
new java.awt.Dimension(1500, 10));
570 setPreferredSize(
new java.awt.Dimension(1500, 44));
572 otherCasesPanel.setPreferredSize(
new java.awt.Dimension(1500, 144));
574 tableContainerPanel.setPreferredSize(
new java.awt.Dimension(1500, 63));
576 tableScrollPane.setPreferredSize(
new java.awt.Dimension(1500, 30));
578 otherCasesTable.setAutoCreateRowSorter(
true);
579 otherCasesTable.setModel(tableModel);
580 otherCasesTable.setToolTipText(
org.openide.util.NbBundle.getMessage(
DataContentViewerOtherCases.class,
"DataContentViewerOtherCases.table.toolTip.text"));
581 otherCasesTable.setComponentPopupMenu(rightClickPopupMenu);
582 otherCasesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_INTERVAL_SELECTION);
583 tableScrollPane.setViewportView(otherCasesTable);
585 tableStatusPanel.setPreferredSize(
new java.awt.Dimension(1500, 16));
587 tableStatusPanelLabel.setForeground(
new java.awt.Color(255, 0, 51));
589 javax.swing.GroupLayout tableStatusPanelLayout =
new javax.swing.GroupLayout(tableStatusPanel);
590 tableStatusPanel.setLayout(tableStatusPanelLayout);
591 tableStatusPanelLayout.setHorizontalGroup(
592 tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
593 .addGap(0, 0, Short.MAX_VALUE)
594 .addGroup(tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
595 .addGroup(tableStatusPanelLayout.createSequentialGroup()
597 .addComponent(tableStatusPanelLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 780, Short.MAX_VALUE)
600 tableStatusPanelLayout.setVerticalGroup(
601 tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
602 .addGap(0, 16, Short.MAX_VALUE)
603 .addGroup(tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
604 .addGroup(tableStatusPanelLayout.createSequentialGroup()
605 .addComponent(tableStatusPanelLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE)
606 .addGap(0, 0, Short.MAX_VALUE)))
609 javax.swing.GroupLayout tableContainerPanelLayout =
new javax.swing.GroupLayout(tableContainerPanel);
610 tableContainerPanel.setLayout(tableContainerPanelLayout);
611 tableContainerPanelLayout.setHorizontalGroup(
612 tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
613 .addComponent(tableScrollPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
614 .addComponent(tableStatusPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
616 tableContainerPanelLayout.setVerticalGroup(
617 tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
618 .addGroup(tableContainerPanelLayout.createSequentialGroup()
619 .addComponent(tableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
620 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
621 .addComponent(tableStatusPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
625 javax.swing.GroupLayout otherCasesPanelLayout =
new javax.swing.GroupLayout(otherCasesPanel);
626 otherCasesPanel.setLayout(otherCasesPanelLayout);
627 otherCasesPanelLayout.setHorizontalGroup(
628 otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
629 .addGap(0, 1500, Short.MAX_VALUE)
630 .addGroup(otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
631 .addComponent(tableContainerPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
633 otherCasesPanelLayout.setVerticalGroup(
634 otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
635 .addGap(0, 60, Short.MAX_VALUE)
636 .addGroup(otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
637 .addGroup(otherCasesPanelLayout.createSequentialGroup()
638 .addComponent(tableContainerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 60, Short.MAX_VALUE)
642 javax.swing.GroupLayout layout =
new javax.swing.GroupLayout(
this);
643 this.setLayout(layout);
644 layout.setHorizontalGroup(
645 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
646 .addComponent(otherCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
648 layout.setVerticalGroup(
649 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
650 .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
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()
static Case getCurrentCase()
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