diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java
index 19d70deb62..40e7dab750 100644
--- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java
@@ -22,6 +22,7 @@ import org.sleuthkit.autopsy.featureaccess.FeatureAccessUtils;
import com.google.common.annotations.Beta;
import com.google.common.eventbus.Subscribe;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import java.awt.Cursor;
import org.sleuthkit.autopsy.casemodule.multiusercases.CaseNodeData;
import java.awt.Frame;
import java.awt.event.ActionEvent;
@@ -1324,12 +1325,14 @@ public class Case {
* opened via the DirectoryTreeTopComponent 'propertyChange()'
* method on a DATA_SOURCE_ADDED event.
*/
+ mainFrame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
if (hasData) {
CoreComponentControl.openCoreWindows();
} else {
//ensure that the DirectoryTreeTopComponent is open so that it's listener can open the core windows including making it visible.
DirectoryTreeTopComponent.findInstance();
}
+ mainFrame.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
/*
* Reset the main window title to:
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java
index 5161a544ca..89b696c041 100644
--- a/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java
@@ -26,6 +26,7 @@ import java.util.Date;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import javax.swing.JOptionPane;
@@ -167,6 +168,8 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel {
}
} catch (InterruptedException | ExecutionException ex) {
logger.log(Level.WARNING, "Error getting results from Ingest Job Info Panel's refresh worker", ex);
+ } catch (CancellationException ignored){
+ logger.log(Level.INFO, "The refreshing of the IngestJobInfoPanel was cancelled");
}
}
};
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java
index c44b4e2479..501203babc 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java
@@ -90,17 +90,17 @@ public final class DataContentViewerOtherCases extends JPanel implements DataCon
public boolean isSupported(Node node) {
// Is supported if one of the following is true:
- // - The central repo is enabled and the node has correlatable content
- // (either through the MD5 hash of the associated file or through a BlackboardArtifact)
+ // - The central repo is enabled and the node is not null
// - The central repo is disabled and the backing file has a valid MD5 hash
- AbstractFile file = OtherOccurrences.getAbstractFileFromNode(node);
- if (CentralRepository.isEnabled()) {
- return !OtherOccurrences.getCorrelationAttributesFromNode(node, file).isEmpty();
- } else {
+ if (CentralRepository.isEnabled() && node != null) {
+ return true;
+ } else if (node != null){
+ AbstractFile file = OtherOccurrences.getAbstractFileFromNode(node);
return file != null
&& file.getSize() > 0
&& ((file.getMd5Hash() != null) && (!file.getMd5Hash().isEmpty()));
}
+ return false;
}
@Override
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrencesPanel.form b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrencesPanel.form
index 237bfe4ce8..13284ecec9 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrencesPanel.form
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrencesPanel.form
@@ -34,8 +34,6 @@
-
-
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrencesPanel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrencesPanel.java
index c4d0bf0e0a..81fac1ebd6 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrencesPanel.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrencesPanel.java
@@ -35,6 +35,9 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.FutureTask;
import java.util.logging.Level;
import javax.swing.JFileChooser;
import javax.swing.JMenuItem;
@@ -46,7 +49,6 @@ import javax.swing.SwingWorker;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
-import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
@@ -71,7 +73,6 @@ public final class OtherOccurrencesPanel extends javax.swing.JPanel {
private static final CorrelationCaseWrapper NO_ARTIFACTS_CASE = new CorrelationCaseWrapper(Bundle.OtherOccurrencesPanel_table_noArtifacts());
private static final CorrelationCaseWrapper NO_RESULTS_CASE = new CorrelationCaseWrapper(Bundle.OtherOccurrencesPanel_table_noResultsFound());
- private static final CorrelationCaseWrapper LOADING_CASE = new CorrelationCaseWrapper(Bundle.OtherOccurrencesPanel_table_loadingResults());
private static final Logger logger = Logger.getLogger(OtherOccurrencesPanel.class.getName());
private static final long serialVersionUID = 1L;
private final OtherOccurrencesFilesTableModel filesTableModel;
@@ -84,6 +85,11 @@ public final class OtherOccurrencesPanel extends javax.swing.JPanel {
private AbstractFile file = null;
private SwingWorker, ?> worker;
+
+ // Initializing the JFileChooser in a thread to prevent a block on the EDT
+ // see https://stackoverflow.com/questions/49792375/jfilechooser-is-very-slow-when-using-windows-look-and-feel
+ private final FutureTask futureFileChooser = new FutureTask<>(JFileChooser::new);
+ private JFileChooser CSVFileChooser;
/**
* Creates new form OtherOccurrencesPanel
@@ -93,9 +99,11 @@ public final class OtherOccurrencesPanel extends javax.swing.JPanel {
this.casesTableModel = new OtherOccurrencesCasesTableModel();
this.dataSourcesTableModel = new OtherOccurrencesDataSourcesTableModel();
this.correlationAttributes = new ArrayList<>();
- occurrencePanel = new OccurrencePanel();
initComponents();
customizeComponents();
+
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ executor.execute(futureFileChooser);
}
private void customizeComponents() {
@@ -245,6 +253,18 @@ public final class OtherOccurrencesPanel extends javax.swing.JPanel {
private void saveToCSV() throws NoCurrentCaseException {
if (casesTableModel.getRowCount() > 0) {
+
+ if(CSVFileChooser == null) {
+ try{
+ CSVFileChooser = futureFileChooser.get();
+ } catch (InterruptedException | ExecutionException ex) {
+ // If something happened with the thread try and
+ // initalized the chooser now
+ logger.log(Level.WARNING, "A failure occurred in the JFileChooser background thread");
+ CSVFileChooser = new JFileChooser();
+ }
+ }
+
Calendar now = Calendar.getInstance();
String fileName = String.format("%1$tY%1$tm%1$te%1$tI%1$tM%1$tS_other_data_sources.csv", now);
CSVFileChooser.setCurrentDirectory(new File(Case.getCurrentCaseThrows().getExportDirectory()));
@@ -258,8 +278,8 @@ public final class OtherOccurrencesPanel extends javax.swing.JPanel {
if (!selectedFile.getName().endsWith(".csv")) { // NON-NLS
selectedFile = new File(selectedFile.toString() + ".csv"); // NON-NLS
}
- CSVWorker worker = new CSVWorker(selectedFile, file, dataSourceName, deviceId, Collections.unmodifiableCollection(correlationAttributes));
- worker.execute();
+ CSVWorker csvWorker = new CSVWorker(selectedFile, file, dataSourceName, deviceId, Collections.unmodifiableCollection(correlationAttributes));
+ csvWorker.execute();
}
}
}
@@ -685,7 +705,6 @@ public final class OtherOccurrencesPanel extends javax.swing.JPanel {
exportToCSVMenuItem = new javax.swing.JMenuItem();
showCaseDetailsMenuItem = new javax.swing.JMenuItem();
showCommonalityMenuItem = new javax.swing.JMenuItem();
- CSVFileChooser = new javax.swing.JFileChooser();
tableContainerPanel = new javax.swing.JPanel();
tablesViewerSplitPane = new javax.swing.JSplitPane();
caseDatasourceFileSplitPane = new javax.swing.JSplitPane();
@@ -704,12 +723,12 @@ public final class OtherOccurrencesPanel extends javax.swing.JPanel {
filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0));
rightClickPopupMenu.addPopupMenuListener(new javax.swing.event.PopupMenuListener() {
- public void popupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent evt) {
- rightClickPopupMenuPopupMenuWillBecomeVisible(evt);
+ public void popupMenuCanceled(javax.swing.event.PopupMenuEvent evt) {
}
public void popupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent evt) {
}
- public void popupMenuCanceled(javax.swing.event.PopupMenuEvent evt) {
+ public void popupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent evt) {
+ rightClickPopupMenuPopupMenuWillBecomeVisible(evt);
}
});
@@ -857,7 +876,6 @@ public final class OtherOccurrencesPanel extends javax.swing.JPanel {
// Variables declaration - do not modify//GEN-BEGIN:variables
- private javax.swing.JFileChooser CSVFileChooser;
private javax.swing.JSplitPane caseDatasourceFileSplitPane;
private javax.swing.JSplitPane caseDatasourceSplitPane;
private javax.swing.JScrollPane caseScrollPane;
diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java
index aad1fe79a8..b61abfceee 100755
--- a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java
+++ b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java
@@ -130,25 +130,7 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
@Override
public boolean isSupported(Node node) {
- BlackboardArtifact artifact = node.getLookup().lookup(BlackboardArtifact.class);
-
- try {
- if (artifact != null) {
- if (artifact.getSleuthkitCase().getAbstractFileById(artifact.getObjectID()) != null) {
- return true;
- }
- } else {
- if (node.getLookup().lookup(AbstractFile.class) != null) {
- return true;
- }
- }
- } catch (TskCoreException ex) {
- logger.log(Level.SEVERE, String.format(
- "Exception while trying to retrieve a Content instance from the BlackboardArtifact '%s' (id=%d).",
- artifact.getDisplayName(), artifact.getArtifactID()), ex);
- }
-
- return false;
+ return node != null && node.getLookup().lookup(AbstractFile.class) != null;
}
@Override
diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java
index 06b0a42fb7..177c397c78 100644
--- a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java
+++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java
@@ -34,6 +34,9 @@ import java.util.Collections;
import java.util.List;
import static java.util.Objects.nonNull;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.FutureTask;
import java.util.logging.Level;
import java.util.stream.Collectors;
import javafx.application.Platform;
@@ -150,7 +153,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
private final JMenuItem exportTagsMenuItem;
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
- private final JFileChooser exportChooser;
+ private JFileChooser exportChooser;
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
private final JFXPanel fxPanel;
@@ -189,10 +192,10 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
private Task readImageFileTask;
private volatile ImageTransforms imageTransforms;
-
- static {
- ImageIO.scanForPlugins();
- }
+
+ // Initializing the JFileChooser in a thread to prevent a block on the EDT
+ // see https://stackoverflow.com/questions/49792375/jfilechooser-is-very-slow-when-using-windows-look-and-feel
+ private final FutureTask futureFileChooser = new FutureTask<>(JFileChooser::new);
/**
* Constructs a media image file viewer implemented as a Swing panel that
@@ -210,9 +213,9 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
initComponents();
imageTransforms = new ImageTransforms(0, 0, true);
-
- exportChooser = new JFileChooser();
- exportChooser.setDialogTitle(Bundle.MediaViewImagePanel_fileChooserTitle());
+
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ executor.execute(futureFileChooser);
//Build popupMenu when Tags Menu button is pressed.
imageTaggingOptions = new JPopupMenu();
@@ -1043,6 +1046,18 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
final AbstractFile file = imageFile;
tagsGroup.clearFocus();
SwingUtilities.invokeLater(() -> {
+
+ if(exportChooser == null) {
+ try {
+ exportChooser = futureFileChooser.get();
+ } catch (InterruptedException | ExecutionException ex) {
+ // If something happened with the thread try and
+ // initalized the chooser now
+ logger.log(Level.WARNING, "A failure occurred in the JFileChooser background thread");
+ exportChooser = new JFileChooser();
+ }
+ }
+
exportChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
//Always base chooser location to export folder
exportChooser.setCurrentDirectory(new File(Case.getCurrentCase().getExportDirectory()));
diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java
index bd3671e44b..112ea3523c 100644
--- a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java
+++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java
@@ -150,7 +150,7 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer {
ContentViewerHtmlStyles.getTextClassName(),
EscapeUtil.escapeHtml(key),
ContentViewerHtmlStyles.getTextClassName(),
- EscapeUtil.escapeHtml(key)
+ EscapeUtil.escapeHtml(value)
));
}
diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/textcontentviewer/TextContentViewerPanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/textcontentviewer/TextContentViewerPanel.java
index 7c80d606fd..62062cbc95 100644
--- a/Core/src/org/sleuthkit/autopsy/contentviewers/textcontentviewer/TextContentViewerPanel.java
+++ b/Core/src/org/sleuthkit/autopsy/contentviewers/textcontentviewer/TextContentViewerPanel.java
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
- * Copyright 2019 Basis Technology Corp.
+ * Copyright 2019-2021 Basis Technology Corp.
* Contact: carrier sleuthkit org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -79,9 +79,9 @@ public class TextContentViewerPanel extends javax.swing.JPanel implements DataCo
}
/**
- * Determine whether the content viewer which displays this panel isSupported.
- * This panel is supported if any of the TextViewer's displayed in it are
- * supported.
+ * Determine whether the content viewer which displays this panel
+ * isSupported. This panel is supported if any of the TextViewer's displayed
+ * in it are supported.
*
* @param node
*
@@ -213,7 +213,7 @@ public class TextContentViewerPanel extends javax.swing.JPanel implements DataCo
// Get and set current selected tab
int currentTab = pane.getSelectedIndex();
- if (currentTab != -1) {
+ if (currentTab != -1 && pane.isEnabledAt(currentTab)) {
UpdateWrapper dcv = textViewers.get(currentTab);
if (dcv.isOutdated()) {
// change the cursor to "waiting cursor" for this operation
diff --git a/Core/src/org/sleuthkit/autopsy/core/Installer.java b/Core/src/org/sleuthkit/autopsy/core/Installer.java
index 5bd649e8cb..7411377733 100644
--- a/Core/src/org/sleuthkit/autopsy/core/Installer.java
+++ b/Core/src/org/sleuthkit/autopsy/core/Installer.java
@@ -33,6 +33,7 @@ import java.util.logging.Handler;
import java.util.logging.Level;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
+import javax.imageio.ImageIO;
import net.sf.sevenzipjbinding.SevenZip;
import net.sf.sevenzipjbinding.SevenZipNativeInitializationException;
import org.apache.commons.io.FileUtils;
@@ -44,6 +45,7 @@ import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.actions.IngestRunningCheck;
import org.sleuthkit.autopsy.casemodule.Case;
import static org.sleuthkit.autopsy.core.UserPreferences.SETTINGS_PROPERTIES;
+import org.sleuthkit.autopsy.corelibs.OpenCvLoader;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
@@ -66,6 +68,13 @@ public class Installer extends ModuleInstall {
static {
loadDynLibraries();
+
+ // This call was moved from MediaViewImagePanel so that it is
+ // not called during top level component construction.
+ ImageIO.scanForPlugins();
+
+ // This will cause OpenCvLoader to load its library instead of
+ OpenCvLoader.openCvIsLoaded();
}
private static void loadDynLibraries() {
diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java
index 6ae521de1e..8d9c3a02b9 100644
--- a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java
+++ b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java
@@ -194,7 +194,7 @@ public class ImageUtils {
public static SortedSet getSupportedImageMimeTypes() {
return Collections.unmodifiableSortedSet(SUPPORTED_IMAGE_MIME_TYPES);
}
-
+
/**
* Get the default thumbnail, which is the icon for a file. Used when we can
* not generate a content based thumbnail.
diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java
index 1068c72973..e3bad44705 100644
--- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java
+++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java
@@ -80,6 +80,7 @@ import static org.sleuthkit.autopsy.datamodel.AbstractContentNode.NO_DESCR;
import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
import org.sleuthkit.autopsy.datamodel.utils.FileNameTransTask;
import org.sleuthkit.datamodel.AnalysisResult;
+import org.sleuthkit.datamodel.BlackboardArtifact.Category;
import org.sleuthkit.datamodel.Score;
/**
@@ -109,17 +110,6 @@ public class BlackboardArtifactNode extends AbstractContentNode
-
+
@@ -24,13 +24,11 @@
-
-
-
-
-
-
-
+
+
+
+
+
@@ -42,14 +40,7 @@
-
-
-
-
-
-
-
-
+
@@ -63,78 +54,140 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportVisualPanel1.java b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportVisualPanel1.java
index e98f0b7984..5c1dcc38ac 100644
--- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportVisualPanel1.java
+++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportVisualPanel1.java
@@ -36,6 +36,7 @@ import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.ListCellRenderer;
import javax.swing.ListSelectionModel;
+import javax.swing.border.Border;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.openide.DialogDisplayer;
@@ -271,16 +272,35 @@ final class ReportVisualPanel1 extends JPanel implements ListSelectionListener {
private void initComponents() {
reportModulesLabel = new javax.swing.JLabel();
+ javax.swing.JSplitPane modulesSplitPane = new javax.swing.JSplitPane();
+ javax.swing.JPanel detailsPanel = new javax.swing.JPanel();
configurationPanel = new javax.swing.JPanel();
descriptionScrollPane = new javax.swing.JScrollPane();
descriptionTextPane = new javax.swing.JTextPane();
modulesScrollPane = new javax.swing.JScrollPane();
modulesJList = new javax.swing.JList<>();
- setPreferredSize(new java.awt.Dimension(650, 250));
+ setPreferredSize(new java.awt.Dimension(834, 374));
org.openide.awt.Mnemonics.setLocalizedText(reportModulesLabel, org.openide.util.NbBundle.getMessage(ReportVisualPanel1.class, "ReportVisualPanel1.reportModulesLabel.text")); // NOI18N
+ //Make border on split pane invisible to maintain previous style
+ modulesSplitPane.setUI(new javax.swing.plaf.basic.BasicSplitPaneUI() {
+ @Override
+ public javax.swing.plaf.basic.BasicSplitPaneDivider createDefaultDivider() {
+ javax.swing.plaf.basic.BasicSplitPaneDivider divider = new javax.swing.plaf.basic.BasicSplitPaneDivider(this) {
+ @Override
+ public void setBorder(Border border){
+ //do nothing so border is not visible
+ }
+ };
+ return divider;
+ }
+ });
+ modulesSplitPane.setBorder(null);
+ modulesSplitPane.setDividerSize(8);
+ modulesSplitPane.setResizeWeight(0.5);
+
configurationPanel.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(125, 125, 125)));
configurationPanel.setOpaque(false);
@@ -288,11 +308,11 @@ final class ReportVisualPanel1 extends JPanel implements ListSelectionListener {
configurationPanel.setLayout(configurationPanelLayout);
configurationPanelLayout.setHorizontalGroup(
configurationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGap(0, 432, Short.MAX_VALUE)
+ .addGap(0, 546, Short.MAX_VALUE)
);
configurationPanelLayout.setVerticalGroup(
configurationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGap(0, 168, Short.MAX_VALUE)
+ .addGap(0, 290, Short.MAX_VALUE)
);
descriptionScrollPane.setBorder(null);
@@ -302,6 +322,29 @@ final class ReportVisualPanel1 extends JPanel implements ListSelectionListener {
descriptionTextPane.setOpaque(false);
descriptionScrollPane.setViewportView(descriptionTextPane);
+ javax.swing.GroupLayout detailsPanelLayout = new javax.swing.GroupLayout(detailsPanel);
+ detailsPanel.setLayout(detailsPanelLayout);
+ detailsPanelLayout.setHorizontalGroup(
+ detailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(detailsPanelLayout.createSequentialGroup()
+ .addGap(0, 0, 0)
+ .addGroup(detailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(descriptionScrollPane)
+ .addComponent(configurationPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ .addGap(0, 0, 0))
+ );
+ detailsPanelLayout.setVerticalGroup(
+ detailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(detailsPanelLayout.createSequentialGroup()
+ .addGap(0, 0, 0)
+ .addComponent(descriptionScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(configurationPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addGap(0, 0, 0))
+ );
+
+ modulesSplitPane.setRightComponent(detailsPanel);
+
modulesJList.setBackground(new java.awt.Color(240, 240, 240));
modulesJList.setModel(new javax.swing.AbstractListModel() {
ReportModule[] modules = {};
@@ -311,6 +354,8 @@ final class ReportVisualPanel1 extends JPanel implements ListSelectionListener {
modulesJList.setOpaque(false);
modulesScrollPane.setViewportView(modulesJList);
+ modulesSplitPane.setLeftComponent(modulesScrollPane);
+
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
@@ -318,12 +363,10 @@ final class ReportVisualPanel1 extends JPanel implements ListSelectionListener {
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(reportModulesLabel)
- .addComponent(modulesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 190, javax.swing.GroupLayout.PREFERRED_SIZE))
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(configurationPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
- .addComponent(descriptionScrollPane))
+ .addGroup(layout.createSequentialGroup()
+ .addComponent(reportModulesLabel)
+ .addGap(0, 0, Short.MAX_VALUE))
+ .addComponent(modulesSplitPane))
.addContainerGap())
);
layout.setVerticalGroup(
@@ -332,12 +375,7 @@ final class ReportVisualPanel1 extends JPanel implements ListSelectionListener {
.addContainerGap()
.addComponent(reportModulesLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(layout.createSequentialGroup()
- .addComponent(descriptionScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(configurationPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
- .addComponent(modulesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 208, Short.MAX_VALUE))
+ .addComponent(modulesSplitPane)
.addContainerGap())
);
}// //GEN-END:initComponents
diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportVisualPanel2.form b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportVisualPanel2.form
index b54495fb20..bad6a7a7fa 100644
--- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportVisualPanel2.form
+++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportVisualPanel2.form
@@ -7,7 +7,7 @@
-
+
diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportVisualPanel2.java b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportVisualPanel2.java
index a596eb6c38..5243f2fe63 100644
--- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportVisualPanel2.java
+++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportVisualPanel2.java
@@ -311,7 +311,7 @@ final class ReportVisualPanel2 extends JPanel {
advancedButton = new javax.swing.JButton();
allTaggedResultsRadioButton = new javax.swing.JRadioButton();
- setPreferredSize(new java.awt.Dimension(650, 275));
+ setPreferredSize(new java.awt.Dimension(834, 374));
optionsButtonGroup.add(specificTaggedResultsRadioButton);
org.openide.awt.Mnemonics.setLocalizedText(specificTaggedResultsRadioButton, org.openide.util.NbBundle.getMessage(ReportVisualPanel2.class, "ReportVisualPanel2.specificTaggedResultsRadioButton.text")); // NOI18N
diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java b/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java
index f8dbebe224..12412aae20 100644
--- a/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java
+++ b/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java
@@ -62,6 +62,7 @@ import org.sleuthkit.autopsy.report.ReportProgressPanel;
import org.sleuthkit.caseuco.CaseUcoExporter;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Account;
+import org.sleuthkit.datamodel.AnalysisResult;
import org.sleuthkit.datamodel.Blackboard.BlackboardException;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifactTag;
@@ -69,12 +70,19 @@ import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.CaseDbAccessManager;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentTag;
+import org.sleuthkit.datamodel.DataArtifact;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.FileSystem;
import org.sleuthkit.datamodel.Host;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.LocalFilesDataSource;
+import org.sleuthkit.datamodel.OsAccount;
+import org.sleuthkit.datamodel.OsAccountManager;
+import org.sleuthkit.datamodel.OsAccountManager.NotUserSIDException;
+import org.sleuthkit.datamodel.OsAccountRealm;
+import org.sleuthkit.datamodel.OsAccountRealmManager;
import org.sleuthkit.datamodel.Pool;
+import org.sleuthkit.datamodel.Score;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.SleuthkitCase.CaseDbTransaction;
import org.sleuthkit.datamodel.TagName;
@@ -132,6 +140,12 @@ public class PortableCaseReportModule implements ReportModule {
// Map of old artifact ID to new artifact
private final Map oldArtifactIdToNewArtifact = new HashMap<>();
+
+ // Map of old OS account id to new OS account id
+ private final Map oldOsAccountIdToNewOsAccountId = new HashMap<>();
+
+ // Map of old OS account realm id to new OS account ream id
+ private final Map oldRealmIdToNewRealm = new HashMap<>();
public PortableCaseReportModule() {
}
@@ -392,8 +406,8 @@ public class PortableCaseReportModule implements ReportModule {
// Copy interesting files and results
if (!setNames.isEmpty()) {
try {
- List interestingFiles = currentCase.getSleuthkitCase().getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
- for (BlackboardArtifact art : interestingFiles) {
+ List interestingFiles = currentCase.getSleuthkitCase().getBlackboard().getAnalysisResultsByType(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getTypeID());
+ for (AnalysisResult art : interestingFiles) {
// Check for cancellation
if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
handleCancellation(progressPanel);
@@ -411,8 +425,8 @@ public class PortableCaseReportModule implements ReportModule {
}
try {
- List interestingResults = currentCase.getSleuthkitCase().getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT);
- for (BlackboardArtifact art : interestingResults) {
+ List interestingResults = currentCase.getSleuthkitCase().getBlackboard().getAnalysisResultsByType(BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getTypeID());
+ for (AnalysisResult art : interestingResults) {
// Check for cancellation
if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
handleCancellation(progressPanel);
@@ -936,9 +950,6 @@ public class PortableCaseReportModule implements ReportModule {
String.join(",", oldAssociatedAttribute.getSources()), newAssociatedArtifact.getArtifactID()));
}
- // Create the new artifact
- int newArtifactTypeId = getNewArtifactTypeId(artifactToCopy);
- BlackboardArtifact newArtifact = portableSkCase.newBlackboardArtifact(newArtifactTypeId, newContentId);
List oldAttrs = artifactToCopy.getAttributes();
// Copy over each attribute, making sure the type is in the new case.
@@ -977,8 +988,62 @@ public class PortableCaseReportModule implements ReportModule {
throw new TskCoreException("Unexpected attribute value type found: " + oldAttr.getValueType().getLabel()); // NON-NLS
}
}
-
- newArtifact.addAttributes(newAttrs);
+ // Create the new artifact
+ int newArtifactTypeId = getNewArtifactTypeId(artifactToCopy);
+ BlackboardArtifact.Type newArtifactType = portableSkCase.getBlackboard().getArtifactType(newArtifactTypeId);
+ BlackboardArtifact newArtifact;
+
+ // First, check if the artifact being copied is an AnalysisResult or a DataArtifact. If it
+ // is neither, attempt to reload it as the appropriate subclass.
+ if (!((artifactToCopy instanceof AnalysisResult) || (artifactToCopy instanceof DataArtifact))) {
+ try {
+ if (newArtifactType.getCategory().equals(BlackboardArtifact.Category.ANALYSIS_RESULT)) {
+ AnalysisResult ar = currentCase.getSleuthkitCase().getBlackboard().getAnalysisResultById(artifactToCopy.getId());
+ if (ar != null) {
+ artifactToCopy = ar;
+ }
+ } else {
+ DataArtifact da = currentCase.getSleuthkitCase().getBlackboard().getDataArtifactById(artifactToCopy.getId());
+ if (da != null) {
+ artifactToCopy = da;
+ }
+ }
+ } catch (TskCoreException ex) {
+ // If the lookup failed, just use the orginal BlackboardArtifact
+ }
+ }
+
+ try {
+ if (artifactToCopy instanceof AnalysisResult) {
+ AnalysisResult analysisResultToCopy = (AnalysisResult) artifactToCopy;
+ newArtifact = portableSkCase.getBlackboard().newAnalysisResult(newArtifactType, newContentId,
+ newIdToContent.get(newContentId).getDataSource().getId(), analysisResultToCopy.getScore(),
+ analysisResultToCopy.getConclusion(), analysisResultToCopy.getConfiguration(),
+ analysisResultToCopy.getJustification(), newAttrs).getAnalysisResult();
+ } else if (artifactToCopy instanceof DataArtifact) {
+ DataArtifact dataArtifactToCopy = (DataArtifact) artifactToCopy;
+ Long newOsAccountId = null;
+ if (dataArtifactToCopy.getOsAccountObjectId().isPresent()) {
+ copyOsAccount(dataArtifactToCopy.getOsAccountObjectId().get());
+ newOsAccountId = oldOsAccountIdToNewOsAccountId.get((dataArtifactToCopy.getOsAccountObjectId().get()));
+ }
+ newArtifact = portableSkCase.getBlackboard().newDataArtifact(newArtifactType, newContentId,
+ newIdToContent.get(newContentId).getDataSource().getId(),
+ newAttrs, newOsAccountId);
+ } else {
+ if (newArtifactType.getCategory().equals(BlackboardArtifact.Category.ANALYSIS_RESULT)) {
+ newArtifact = portableSkCase.getBlackboard().newAnalysisResult(newArtifactType, newContentId,
+ newIdToContent.get(newContentId).getDataSource().getId(), Score.SCORE_NONE,
+ null, null, null, newAttrs).getAnalysisResult();
+ } else {
+ newArtifact = portableSkCase.getBlackboard().newDataArtifact(newArtifactType, newContentId,
+ newIdToContent.get(newContentId).getDataSource().getId(),
+ newAttrs, null);
+ }
+ }
+ } catch (BlackboardException ex) {
+ throw new TskCoreException("Error copying artifact with ID: " + artifactToCopy.getId());
+ }
oldArtifactIdToNewArtifact.put(artifactToCopy.getArtifactID(), newArtifact);
return newArtifact;
@@ -1088,6 +1153,14 @@ public class PortableCaseReportModule implements ReportModule {
newHost = portableSkCase.getHostManager().newHost(oldHost.getName());
}
+ // Copy the associated OS account (if needed) before beginning transaction.
+ if (content instanceof AbstractFile) {
+ AbstractFile file = (AbstractFile) content;
+ if (file.getOsAccountObjectId().isPresent()) {
+ copyOsAccount(file.getOsAccountObjectId().get());
+ }
+ }
+
CaseDbTransaction trans = portableSkCase.beginTransaction();
try {
if (content instanceof Image) {
@@ -1140,10 +1213,16 @@ public class PortableCaseReportModule implements ReportModule {
// Construct the relative path to the copied file
String relativePath = FILE_FOLDER_NAME + File.separator + exportSubFolder + File.separator + fileName;
+ Long newOsAccountId = null;
+ if (abstractFile.getOsAccountObjectId().isPresent()) {
+ newOsAccountId = oldOsAccountIdToNewOsAccountId.get(abstractFile.getOsAccountObjectId().get());
+ }
+
newContent = portableSkCase.addLocalFile(abstractFile.getName(), relativePath, abstractFile.getSize(),
abstractFile.getCtime(), abstractFile.getCrtime(), abstractFile.getAtime(), abstractFile.getMtime(),
abstractFile.getMd5Hash(), abstractFile.getSha256Hash(), abstractFile.getKnown(), abstractFile.getMIMEType(),
- true, TskData.EncodingType.NONE,
+ true, TskData.EncodingType.NONE,
+ newOsAccountId, abstractFile.getOwnerUid().orElse(null),
newParent, trans);
} catch (IOException ex) {
throw new TskCoreException("Error copying file " + abstractFile.getName() + " with original obj ID "
@@ -1166,6 +1245,72 @@ public class PortableCaseReportModule implements ReportModule {
newIdToContent.put(newContent.getId(), newContent);
return oldIdToNewContent.get(content.getId()).getId();
}
+
+ /**
+ * Copy an OS Account to the new case and add it to the oldOsAccountIdToNewOsAccountId map.
+ * Will also copy the associated realm.
+ *
+ * @param oldOsAccountId The OS account id in the current case.
+ */
+ private void copyOsAccount(Long oldOsAccountId) throws TskCoreException {
+ // If it has already been copied, we're done.
+ if (oldOsAccountIdToNewOsAccountId.containsKey(oldOsAccountId)) {
+ return;
+ }
+
+ // Load the OS account from the current case.
+ OsAccountManager oldOsAcctManager = currentCase.getSleuthkitCase().getOsAccountManager();
+ OsAccount oldOsAccount = oldOsAcctManager.getOsAccountByObjectId(oldOsAccountId);
+
+ // Load the realm associated with the OS account.
+ OsAccountRealmManager oldRealmManager = currentCase.getSleuthkitCase().getOsAccountRealmManager();
+ OsAccountRealm oldRealm = oldRealmManager.getRealmByRealmId(oldOsAccount.getRealmId());
+
+ // Copy the realm to the portable case if necessary.
+ if (!oldRealmIdToNewRealm.containsKey(oldOsAccount.getRealmId())) {
+ OsAccountRealmManager newRealmManager = portableSkCase.getOsAccountRealmManager();
+
+ Host host = null;
+ if (oldRealm.getScopeHost().isPresent()) {
+ host = oldRealm.getScopeHost().get();
+ } else {
+ if (oldRealm.getScope().equals(OsAccountRealm.RealmScope.DOMAIN)) {
+ // This is a workaround to get around needing a new method for copying the realm.
+ // The host won't be stored since it's a domain-scoped realm.
+ List hosts = portableSkCase.getHostManager().getAllHosts();
+ if (hosts.isEmpty()) {
+ throw new TskCoreException("Failed to copy OsAccountRealm with ID=" + oldOsAccount.getRealmId() + " because there are no hosts in the case");
+ }
+ host = hosts.get(0);
+ } else {
+ throw new TskCoreException("Failed to copy OsAccountRealm with ID=" + oldOsAccount.getRealmId() + " because it is non-domain scoped but has no scope host");
+ }
+ }
+
+ // We currently only support one realm name.
+ String realmName = null;
+ List names = oldRealm.getRealmNames();
+ if (!names.isEmpty()) {
+ realmName = names.get(0);
+ }
+
+ try {
+ OsAccountRealm newRealm = newRealmManager.newWindowsRealm(oldRealm.getRealmAddr().orElse(null), realmName, host, oldRealm.getScope());
+ oldRealmIdToNewRealm.put(oldOsAccount.getRealmId(), newRealm);
+ } catch (NotUserSIDException ex) {
+ throw new TskCoreException("Failed to copy OsAccountRealm with ID=" + oldOsAccount.getRealmId(), ex);
+ }
+ }
+
+ OsAccountManager newOsAcctManager = portableSkCase.getOsAccountManager();
+ try {
+ OsAccount newOsAccount = newOsAcctManager.newWindowsOsAccount(oldOsAccount.getAddr().orElse(null),
+ oldOsAccount.getLoginName().orElse(null), oldRealmIdToNewRealm.get(oldOsAccount.getRealmId()));
+ oldOsAccountIdToNewOsAccountId.put(oldOsAccountId, newOsAccount.getId());
+ } catch (NotUserSIDException ex) {
+ throw new TskCoreException("Failed to copy OsAccount with ID=" + oldOsAccount.getId(), ex);
+ }
+ }
/**
* Copy path ID attribute to new case along with the referenced file.
@@ -1344,6 +1489,8 @@ public class PortableCaseReportModule implements ReportModule {
oldArtTypeIdToNewArtTypeId.clear();
oldAttrTypeIdToNewAttrType.clear();
oldArtifactIdToNewArtifact.clear();
+ oldOsAccountIdToNewOsAccountId.clear();
+ oldRealmIdToNewRealm.clear();
closePortableCaseDatabase();