Merge branch 'develop' of https://github.com/briangsweeney/autopsy into 3870-pure

This commit is contained in:
Brian Sweeney
2018-06-14 15:39:58 -06:00
200 changed files with 3914 additions and 1548 deletions
-5
View File
@@ -21,11 +21,6 @@
</target>
<target name="get-thirdparty-dependencies" description="get third-party dependencies">
<!--Copy openCV dependencies to release-->
<copy todir="${modules.dir}" >
<fileset dir="${thirdparty.dir}/opencv" />
</copy>
<!--Copy photorec to release-->
<copy todir="${basedir}/release/photorec_exec" >
<fileset dir="${thirdparty.dir}/photorec_exec"/>
+1 -2
View File
@@ -3,7 +3,7 @@ file.reference.c3p0-0.9.5.jar=release/modules/ext/c3p0-0.9.5.jar
file.reference.commons-compress-1.14.jar=release/modules/ext/commons-compress-1.14.jar
file.reference.commons-dbcp2-2.1.1.jar=release\\modules\\ext\\commons-dbcp2-2.1.1.jar
file.reference.commons-pool2-2.4.2.jar=release\\modules\\ext\\commons-pool2-2.4.2.jar
file.reference.dd-plist-1.20.jar=release\\modules\\ext\\dd-plist-1.20.jar
file.reference.dd-plist-1.20.jar=release/modules/ext/dd-plist-1.20.jar
file.reference.jdom-2.0.5-contrib.jar=release/modules/ext/jdom-2.0.5-contrib.jar
file.reference.jdom-2.0.5.jar=release/modules/ext/jdom-2.0.5.jar
file.reference.jgraphx-v3.8.0.jar=release/modules/ext/jgraphx-v3.8.0.jar
@@ -12,7 +12,6 @@ file.reference.jython-standalone-2.7.0.jar=release/modules/ext/jython-standalone
file.reference.mchange-commons-java-0.2.9.jar=release/modules/ext/mchange-commons-java-0.2.9.jar
file.reference.metadata-extractor-2.10.1.jar=release/modules/ext/metadata-extractor-2.10.1.jar
file.reference.postgresql-9.4.1211.jre7.jar=release/modules/ext/postgresql-9.4.1211.jre7.jar
file.reference.opencv-248.jar=release/modules/ext/opencv-248.jar
file.reference.Rejistry-1.0-SNAPSHOT.jar=release/modules/ext/Rejistry-1.0-SNAPSHOT.jar
file.reference.sevenzipjbinding-AllPlatforms.jar=release/modules/ext/sevenzipjbinding-AllPlatforms.jar
file.reference.sevenzipjbinding.jar=release/modules/ext/sevenzipjbinding.jar
+48 -56
View File
@@ -339,6 +339,10 @@
<package>org.sleuthkit.autopsy.report</package>
<package>org.sleuthkit.datamodel</package>
</public-packages>
<class-path-extension>
<runtime-relative-path>ext/jackcess-2.1.8.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jackcess-2.1.8.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/zookeeper-3.4.6.jar</runtime-relative-path>
<binary-origin>release/modules/ext/zookeeper-3.4.6.jar</binary-origin>
@@ -348,33 +352,33 @@
<binary-origin>release/modules/ext/jdom-2.0.5.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/sleuthkit-postgresql-4.6.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sleuthkit-postgresql-4.6.1.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/opencv-248.jar</runtime-relative-path>
<binary-origin>release/modules/ext/opencv-248.jar</binary-origin>
<runtime-relative-path>ext/cxf-rt-transports-http-3.0.16.jar</runtime-relative-path>
<binary-origin>release/modules/ext/cxf-rt-transports-http-3.0.16.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/curator-framework-2.8.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/curator-framework-2.8.0.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/commons-dbcp2-2.1.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/commons-dbcp2-2.1.1.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jgraphx-v3.8.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jgraphx-v3.8.0.jar</binary-origin>
<runtime-relative-path>ext/bcprov-jdk15on-1.54.jar</runtime-relative-path>
<binary-origin>release/modules/ext/bcprov-jdk15on-1.54.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/commons-compress-1.14.jar</runtime-relative-path>
<binary-origin>release/modules/ext/commons-compress-1.14.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/fontbox-2.0.8.jar</runtime-relative-path>
<binary-origin>release/modules/ext/fontbox-2.0.8.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/commons-dbcp2-2.1.1.jar</runtime-relative-path>
<binary-origin>release\modules\ext\commons-dbcp2-2.1.1.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jgraphx-v3.8.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jgraphx-v3.8.0.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jython-standalone-2.7.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jython-standalone-2.7.0.jar</binary-origin>
@@ -387,6 +391,14 @@
<runtime-relative-path>ext/mchange-commons-java-0.2.9.jar</runtime-relative-path>
<binary-origin>release/modules/ext/mchange-commons-java-0.2.9.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/cxf-core-3.0.16.jar</runtime-relative-path>
<binary-origin>release/modules/ext/cxf-core-3.0.16.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/javax.ws.rs-api-2.0.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/javax.ws.rs-api-2.0.1.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/postgresql-9.4.1211.jre7.jar</runtime-relative-path>
<binary-origin>release/modules/ext/postgresql-9.4.1211.jre7.jar</binary-origin>
@@ -399,6 +411,10 @@
<runtime-relative-path>ext/metadata-extractor-2.10.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/metadata-extractor-2.10.1.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/sleuthkit-postgresql-4.6.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sleuthkit-postgresql-4.6.1.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/tika-core-1.17.jar</runtime-relative-path>
<binary-origin>release/modules/ext/tika-core-1.17.jar</binary-origin>
@@ -411,58 +427,18 @@
<runtime-relative-path>ext/curator-client-2.8.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/curator-client-2.8.0.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/bcprov-jdk15on-1.54.jar</runtime-relative-path>
<binary-origin>release/modules/ext/bcprov-jdk15on-1.54.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jackcess-2.1.8.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jackcess-2.1.8.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jackcess-encrypt-2.1.2.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jackcess-encrypt-2.1.2.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jempbox-1.8.13.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jempbox-1.8.13.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/javax.ws.rs-api-2.0.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/javax.ws.rs-api-2.0.1.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/cxf-rt-rs-client-3.0.16.jar</runtime-relative-path>
<binary-origin>release/modules/ext/cxf-rt-rs-client-3.0.16.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/cxf-rt-transports-http-3.0.16.jar</runtime-relative-path>
<binary-origin>release/modules/ext/cxf-rt-transports-http-3.0.16.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/cxf-core-3.0.16.jar</runtime-relative-path>
<binary-origin>release/modules/ext/cxf-core-3.0.16.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/cxf-rt-frontend-jaxrs-3.0.16.jar</runtime-relative-path>
<binary-origin>release/modules/ext/cxf-rt-frontend-jaxrs-3.0.16.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/tika-parsers-1.17.jar</runtime-relative-path>
<binary-origin>release/modules/ext/tika-parsers-1.17.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/fontbox-2.0.8.jar</runtime-relative-path>
<binary-origin>release/modules/ext/fontbox-2.0.8.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/pdfbox-2.0.8.jar</runtime-relative-path>
<binary-origin>release/modules/ext/pdfbox-2.0.8.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/pdfbox-tools-2.0.8.jar</runtime-relative-path>
<binary-origin>release/modules/ext/pdfbox-tools-2.0.8.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/tika-parsers-1.17.jar</runtime-relative-path>
<binary-origin>release/modules/ext/tika-parsers-1.17.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/sqlite-jdbc-3.8.11.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sqlite-jdbc-3.8.11.jar</binary-origin>
@@ -483,6 +459,14 @@
<runtime-relative-path>ext/dd-plist-1.20.jar</runtime-relative-path>
<binary-origin>release/modules/ext/dd-plist-1.20.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jempbox-1.8.13.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jempbox-1.8.13.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/cxf-rt-rs-client-3.0.16.jar</runtime-relative-path>
<binary-origin>release/modules/ext/cxf-rt-rs-client-3.0.16.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/sevenzipjbinding-AllPlatforms.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sevenzipjbinding-AllPlatforms.jar</binary-origin>
@@ -491,6 +475,10 @@
<runtime-relative-path>ext/commons-pool2-2.4.2.jar</runtime-relative-path>
<binary-origin>release\modules\ext\commons-pool2-2.4.2.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jackcess-encrypt-2.1.2.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jackcess-encrypt-2.1.2.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jsoup-1.10.3.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jsoup-1.10.3.jar</binary-origin>
@@ -499,6 +487,10 @@
<runtime-relative-path>ext/jdom-2.0.5-contrib.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jdom-2.0.5-contrib.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/pdfbox-2.0.8.jar</runtime-relative-path>
<binary-origin>release/modules/ext/pdfbox-2.0.8.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/c3p0-0.9.5.jar</runtime-relative-path>
<binary-origin>release/modules/ext/c3p0-0.9.5.jar</binary-origin>
@@ -83,7 +83,7 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
*/
// @@@ This user interface has some significant usability issues and needs
// to be reworked.
private class TagMenu extends JMenu {
private final class TagMenu extends JMenu {
private static final long serialVersionUID = 1L;
@@ -99,13 +99,8 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS
}
// Create a "Quick Tag" sub-menu.
JMenu quickTagMenu = new JMenu(NbBundle.getMessage(this.getClass(), "AddTagAction.quickTag"));
add(quickTagMenu);
// Each tag name in the current set of tags gets its own menu item in
// the "Quick Tags" sub-menu. Selecting one of these menu items adds
// a tag with the associated tag name.
// Create a menu item for each of the existing and visible tags.
// Selecting one of these menu items adds a tag with the associated tag name.
if (null != tagNamesMap && !tagNamesMap.isEmpty()) {
for (Map.Entry<String, TagName> entry : tagNamesMap.entrySet()) {
String tagDisplayName = entry.getKey();
@@ -119,28 +114,15 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
tagNameItem.addActionListener((ActionEvent e) -> {
getAndAddTag(entry.getKey(), entry.getValue(), NO_COMMENT);
});
quickTagMenu.add(tagNameItem);
add(tagNameItem);
}
} else {
JMenuItem empty = new JMenuItem(NbBundle.getMessage(this.getClass(), "AddTagAction.noTags"));
empty.setEnabled(false);
quickTagMenu.add(empty);
}
if (getItemCount() > 0) {
addSeparator();
}
quickTagMenu.addSeparator();
// The "Quick Tag" menu also gets an "Choose Tag..." menu item.
// Selecting this item initiates a dialog that can be used to create
// or select a tag name and adds a tag with the resulting name.
JMenuItem newTagMenuItem = new JMenuItem(NbBundle.getMessage(this.getClass(), "AddTagAction.newTag"));
newTagMenuItem.addActionListener((ActionEvent e) -> {
TagName tagName = GetTagNameDialog.doDialog();
if (null != tagName) {
addTag(tagName, NO_COMMENT);
}
});
quickTagMenu.add(newTagMenuItem);
// Create a "Choose Tag and Comment..." menu item. Selecting this item initiates
// a dialog that can be used to create or select a tag name with an
// optional comment and adds a tag with the resulting name.
@@ -153,6 +135,19 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
}
});
add(tagAndCommentItem);
// Create a "New Tag..." menu item.
// Selecting this item initiates a dialog that can be used to create
// or select a tag name and adds a tag with the resulting name.
JMenuItem newTagMenuItem = new JMenuItem(NbBundle.getMessage(this.getClass(), "AddTagAction.newTag"));
newTagMenuItem.addActionListener((ActionEvent e) -> {
TagName tagName = GetTagNameDialog.doDialog();
if (null != tagName) {
addTag(tagName, NO_COMMENT);
}
});
add(newTagMenuItem);
}
/**
@@ -46,8 +46,12 @@ import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
/**
* Displays existing tag names, and allows the creation of new tags.
*/
@Messages({"GetTagNameDialog.descriptionLabel.text=Description:",
"GetTagNameDialog.notableCheckbox.text=Tag indicates item is notable."})
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public class GetTagNameDialog extends JDialog {
private static final long serialVersionUID = 1L;
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2012 Basis Technology Corp.
* Copyright 2012-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,16 +19,14 @@
package org.sleuthkit.autopsy.casemodule;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JProgressBar;
import org.openide.WizardDescriptor;
import org.openide.util.NbBundle;
/**
* visual component to display progress bar and status updates while adding an
* image in the wizard
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class AddImageWizardAddingProgressVisual extends javax.swing.JPanel {
private static final String ADDING_DATA_SOURCE_COMPLETE = NbBundle
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -37,8 +37,8 @@ import org.sleuthkit.autopsy.coreutils.Logger;
/**
* visual component for the first panel of add image wizard. Allows the user to
* choose the data source type and then select the data source
*
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class AddImageWizardDataSourceSettingsVisual extends JPanel {
private static final Logger logger = Logger.getLogger(AddImageWizardDataSourceSettingsVisual.class.getName());
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2014 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,8 +25,8 @@ import javax.swing.JPanel;
/**
* UI panel for the ingest job configuration wizard panel of the add data source
* wizard.
*
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class AddImageWizardIngestConfigVisual extends JPanel {
private final JPanel ingestPanel;
@@ -46,6 +46,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
* Panel which displays the available DataSourceProcessors and allows selection
* of one
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class AddImageWizardSelectDspVisual extends JPanel {
private static final Logger logger = Logger.getLogger(AddImageWizardSelectDspVisual.class.getName());
@@ -49,8 +49,8 @@ import org.sleuthkit.autopsy.datamodel.EmptyNode;
*
* Used to display a list of multi user cases and allow the user to open one of
* them.
*
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class CaseBrowser extends javax.swing.JPanel implements ExplorerManager.Provider {
private static final long serialVersionUID = 1L;
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -32,6 +32,7 @@ import org.openide.windows.WindowManager;
* Panel for displaying the case information, including both case details and
* ingest job history.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class CaseInformationPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -31,10 +31,11 @@ import org.sleuthkit.autopsy.coreutils.Logger;
* A panel that allows the user to view various properties of a case and change
* the display name of the case.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class CasePropertiesPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(CasePropertiesPanel.class.getName());
private static final Logger logger = Logger.getLogger(CasePropertiesPanel.class.getName());
private Case theCase;
/**
@@ -52,7 +53,7 @@ final class CasePropertiesPanel extends javax.swing.JPanel {
try {
theCase = Case.getCurrentCaseThrows();
} catch (NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex);
logger.log(Level.SEVERE, "Exception while getting open case.", ex);
return;
}
lbCaseNameText.setText(theCase.getDisplayName());
@@ -90,7 +91,7 @@ final class CasePropertiesPanel extends javax.swing.JPanel {
currentOrg = correlationCase.getOrg();
}
} catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Unable to access Correlation Case when Central Repo is enabled", ex);
logger.log(Level.SEVERE, "Unable to access Correlation Case when Central Repo is enabled", ex);
}
}
if (currentOrg != null) {
@@ -35,6 +35,7 @@ import org.openide.windows.WindowManager;
/*
* The panel in the default Autopsy startup window.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public class CueBannerPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,9 +22,9 @@ import java.awt.event.ActionListener;
import org.openide.util.NbBundle.Messages;
/**
*
* @author wschaefer
* Panel to allow examiner to edit option case properties.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class EditOptionalCasePropertiesPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
@@ -31,7 +31,6 @@ import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.filechooser.FileFilter;
import org.apache.commons.lang3.StringUtils;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
import static org.sleuthkit.autopsy.casemodule.Bundle.*;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
@@ -46,6 +45,7 @@ import org.sleuthkit.autopsy.coreutils.PathValidator;
* to select a file as well as choose the timezone and whether to ignore orphan
* files in FAT32.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public class ImageFilePanel extends JPanel implements DocumentListener {
private static final Logger logger = Logger.getLogger(ImageFilePanel.class.getName());
@@ -39,6 +39,7 @@ import org.sleuthkit.datamodel.TskCoreException;
/**
* Panel for displaying ingest job history.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public final class IngestJobInfoPanel extends javax.swing.JPanel {
private static final Logger logger = Logger.getLogger(IngestJobInfoPanel.class.getName());
@@ -91,7 +92,7 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel {
"IngestJobInfoPanel.IngestJobTableModel.IngestStatus.header=Ingest Status"})
private class IngestJobTableModel extends AbstractTableModel {
private List<String> columnHeaders = new ArrayList<>();
private final List<String> columnHeaders = new ArrayList<>();
IngestJobTableModel() {
columnHeaders.add(Bundle.IngestJobInfoPanel_IngestJobTableModel_DataSource_header());
@@ -146,8 +147,8 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel {
"IngestJobInfoPanel.IngestModuleTableModel.ModuleVersion.header=Module Version"})
private class IngestModuleTableModel extends AbstractTableModel {
private List<String> columnHeaders = new ArrayList<>();
private IngestJobInfo currJob;
private final List<String> columnHeaders = new ArrayList<>();
private final IngestJobInfo currJob;
IngestModuleTableModel(IngestJobInfo currJob) {
columnHeaders.add(Bundle.IngestJobInfoPanel_IngestModuleTableModel_ModuleName_header());
@@ -34,6 +34,10 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.imagewriter.ImageWriterSettings;
/**
* ImageTypePanel for adding a local disk or partition such as PhysicalDrive0 or
* C:.
*/
@NbBundle.Messages({
"LocalDiskPanel.errorMessage.noOpenCaseTitle=No open case available",
"LocalDiskPanel.errorMessage.noOpenCaseBody=LocalDiskPanel listener couldn't get the open case.",
@@ -45,10 +49,7 @@ import org.sleuthkit.autopsy.imagewriter.ImageWriterSettings;
"LocalDiskPanel.moduleErrorMessage.body=A module caused an error listening to LocalDiskPanel updates. See log to determine which module. Some data could be incomplete.",
"LocalDiskPanel.localDiskMessage.unspecified=Unspecified"
})
/**
* ImageTypePanel for adding a local disk or partition such as PhysicalDrive0 or
* C:.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class LocalDiskPanel extends JPanel {
private static final Logger logger = Logger.getLogger(LocalDiskPanel.class.getName());
@@ -35,6 +35,7 @@ import org.sleuthkit.autopsy.coreutils.PathValidator;
/**
* A panel which allows the user to select local files and/or directories.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class LocalFilesPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
@@ -28,13 +28,14 @@ import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
/**
* Add input wizard subpanel for adding local files / dirs to the case
*/
@Messages({
"LogicalFilesDspPanel.subTypeComboBox.localFilesOption.text=Local files and folders",
"LogicalFilesDspPanel.subTypeComboBox.l01FileOption.text=Logical evidence file (L01)"
})
/**
* Add input wizard subpanel for adding local files / dirs to the case
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class LogicalFilesDspPanel extends JPanel {
private static final long serialVersionUID = 1L;
@@ -35,6 +35,10 @@ import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Dialog to allow the examiner to locate an image when it cannot be found.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class MissingImageDialog extends javax.swing.JDialog {
private static final Logger logger = Logger.getLogger(MissingImageDialog.class.getName());
@@ -50,7 +54,7 @@ class MissingImageDialog extends javax.swing.JDialog {
}
static final String allDesc = NbBundle.getMessage(MissingImageDialog.class, "MissingImageDialog.allDesc.text");
static final GeneralFilter allFilter = new GeneralFilter(allExt, allDesc);
private JFileChooser fc = new JFileChooser();
private final JFileChooser fc = new JFileChooser();
/**
* Instantiate a MissingImageDialog.
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -36,9 +36,10 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
/**
* A panel that allows a user to open cases created by auto ingest.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class MultiUserCasesPanel extends JPanel{
private static final Logger LOGGER = Logger.getLogger(MultiUserCasesPanel.class.getName());
private static final Logger logger = Logger.getLogger(MultiUserCasesPanel.class.getName());
private static final long serialVersionUID = 1L;
private final JDialog parentDialog;
private final CaseBrowser caseBrowserPanel;
@@ -98,7 +99,7 @@ final class MultiUserCasesPanel extends JPanel{
Case.openAsCurrentCase(caseMetadataFilePath);
} catch (CaseActionException ex) {
if (null != ex.getCause() && !(ex.getCause() instanceof CaseActionCancelledException)) {
LOGGER.log(Level.SEVERE, String.format("Error opening case with metadata file path %s", caseMetadataFilePath), ex); //NON-NLS
logger.log(Level.SEVERE, String.format("Error opening case with metadata file path %s", caseMetadataFilePath), ex); //NON-NLS
MessageNotifyUtil.Message.error(ex.getCause().getLocalizedMessage());
}
SwingUtilities.invokeLater(() -> {
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2015 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,9 +18,9 @@
*/
package org.sleuthkit.autopsy.casemodule;
import java.awt.Component;
import org.openide.util.NbBundle;
import java.awt.*;
import java.io.File;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
@@ -33,6 +33,7 @@ import org.sleuthkit.autopsy.coreutils.PathValidator;
/**
* The JPanel for the first page of the new case wizard.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class NewCaseVisualPanel1 extends JPanel implements DocumentListener {
private final JFileChooser fileChooser = new JFileChooser();
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,20 +16,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* NewCaseVisualPanel2.java
*
* Created on Mar 7, 2012, 11:01:48 AM
*/
package org.sleuthkit.autopsy.casemodule;
import org.openide.util.NbBundle;
/**
*
* @author dfickling
* The JPanel for the second page of the new case wizard.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class NewCaseVisualPanel2 extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -35,6 +35,7 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined;
/**
* Panel used by the the open recent case option of the start window.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class OpenRecentCasePanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
@@ -36,9 +36,10 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
* Panel which allows for editing and setting of the case details which are
* optional or otherwise able to be edited.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class OptionalCasePropertiesPanel extends javax.swing.JPanel {
private final static Logger LOGGER = Logger.getLogger(OptionalCasePropertiesPanel.class.getName());
private final static Logger logger = Logger.getLogger(OptionalCasePropertiesPanel.class.getName());
private static final long serialVersionUID = 1L;
private EamOrganization selectedOrg = null;
private java.util.List<EamOrganization> orgs = null;
@@ -66,7 +67,7 @@ final class OptionalCasePropertiesPanel extends javax.swing.JPanel {
try {
openCase = Case.getCurrentCaseThrows();
} catch (NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex);
logger.log(Level.SEVERE, "Exception while getting open case.", ex);
return;
}
caseDisplayNameTextField.setText(openCase.getDisplayName());
@@ -100,9 +101,9 @@ final class OptionalCasePropertiesPanel extends javax.swing.JPanel {
selectedOrg = dbManager.getCase(currentCase).getOrg();
}
} catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Unable to get Organization associated with the case from Central Repo", ex);
logger.log(Level.SEVERE, "Unable to get Organization associated with the case from Central Repo", ex);
} catch (NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex);
logger.log(Level.SEVERE, "Exception while getting open case.", ex);
}
if (selectedOrg != null) {
@@ -145,7 +146,7 @@ final class OptionalCasePropertiesPanel extends javax.swing.JPanel {
});
comboBoxOrgName.setSelectedItem(selectedBeforeLoad);
} catch (EamDbException ex) {
LOGGER.log(Level.WARNING, "Unable to populate list of Organizations from Central Repo", ex);
logger.log(Level.WARNING, "Unable to populate list of Organizations from Central Repo", ex);
}
}
@@ -598,9 +599,9 @@ final class OptionalCasePropertiesPanel extends javax.swing.JPanel {
correlationCase.setNotes(taNotesText.getText());
dbManager.updateCase(correlationCase);
} catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error connecting to central repository database", ex); // NON-NLS
logger.log(Level.SEVERE, "Error connecting to central repository database", ex); // NON-NLS
} catch (NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
logger.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
} finally {
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
@@ -0,0 +1,142 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.centralrepository;
import java.awt.event.ActionEvent;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.TskCoreException;
/**
* An AbstractAction to manage adding and modifying a Central Repository file
* instance comment.
*/
public final class AddEditCentralRepoCommentAction extends AbstractAction {
private static final Logger logger = Logger.getLogger(AddEditCentralRepoCommentAction.class.getName());
private boolean addToDatabase;
private CorrelationAttribute correlationAttribute;
String title;
/**
* Private constructor to create an instance given a CorrelationAttribute.
*
* @param correlationAttribute The correlation attribute to modify.
* @param title The text for the menu item.
*/
private AddEditCentralRepoCommentAction(CorrelationAttribute correlationAttribute, String title) {
super(title);
this.title = title;
this.correlationAttribute = correlationAttribute;
}
/**
* Private constructor to create an instance given an AbstractFile.
*
* @param file The file from which a correlation attribute to modify is
* derived.
* @param title The text for the menu item.
*/
private AddEditCentralRepoCommentAction(AbstractFile file, String title) {
super(title);
this.title = title;
correlationAttribute = EamArtifactUtil.getCorrelationAttributeFromContent(file);
if (correlationAttribute == null) {
addToDatabase = true;
correlationAttribute = EamArtifactUtil.makeCorrelationAttributeFromContent(file);
}
}
@Override
public void actionPerformed(ActionEvent event) {
addEditCentralRepoComment();
}
/**
* Create a Add/Edit dialog for the correlation attribute file instance
* comment. The comment will be updated in the database if the file instance
* exists there, or a new file instance will be added to the database with
* the comment attached otherwise.
*/
public void addEditCentralRepoComment() {
CentralRepoCommentDialog centralRepoCommentDialog = new CentralRepoCommentDialog(correlationAttribute, title);
centralRepoCommentDialog.display();
if (centralRepoCommentDialog.isCommentUpdated()) {
EamDb dbManager;
try {
dbManager = EamDb.getInstance();
if (addToDatabase) {
dbManager.addArtifact(correlationAttribute);
} else {
dbManager.updateAttributeInstanceComment(correlationAttribute);
}
} catch (EamDbException ex) {
logger.log(Level.SEVERE, "Error connecting to Central Repository database.", ex);
}
}
}
/**
* Create an instance labeled "Add/Edit Central Repository Comment" given an
* AbstractFile. This is intended for the result view.
*
* @param file The file from which a correlation attribute to modify is
* derived.
*
* @return The instance.
*
* @throws EamDbException
* @throws NoCurrentCaseException
* @throws TskCoreException
*/
@Messages({"AddEditCentralRepoCommentAction.menuItemText.addEditCentralRepoComment=Add/Edit Central Repository Comment"})
public static AddEditCentralRepoCommentAction createAddEditCentralRepoCommentAction(AbstractFile file) {
return new AddEditCentralRepoCommentAction(file,
Bundle.AddEditCentralRepoCommentAction_menuItemText_addEditCentralRepoComment());
}
/**
* Create an instance labeled "Add/Edit Comment" given a
* CorrelationAttribute. This is intended for the content view.
*
* @param correlationAttribute The correlation attribute to modify.
*
* @return The instance.
*/
@Messages({"AddEditCentralRepoCommentAction.menuItemText.addEditComment=Add/Edit Comment"})
public static AddEditCentralRepoCommentAction createAddEditCommentAction(CorrelationAttribute correlationAttribute) {
return new AddEditCentralRepoCommentAction(correlationAttribute,
Bundle.AddEditCentralRepoCommentAction_menuItemText_addEditComment());
}
}
@@ -5,3 +5,8 @@ OpenIDE-Module-Long-Description=\
Correlation Engine ingest module and central database. \n\n\
The Correlation Engine ingest module stores attributes of artifacts matching selected correlation types into a central database.\n\
Stored attributes are used in future cases to correlate and analyzes files and artifacts during ingest.
CentralRepoCommentDialog.fileLabel.text=File:
CentralRepoCommentDialog.commentLabel.text=Comment:
CentralRepoCommentDialog.pathLabel.text=
CentralRepoCommentDialog.okButton.text=&OK
CentralRepoCommentDialog.cancelButton.text=C&ancel
@@ -0,0 +1,138 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<Properties>
<Property name="defaultCloseOperation" type="int" value="2"/>
<Property name="size" type="java.awt.Dimension" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection component="Form" name="preferredSize" type="property"/>
</Property>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jScrollPane1" pref="500" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="fileLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="pathLabel" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="commentLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="451" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Component id="okButton" min="-2" pref="75" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="cancelButton" min="-2" pref="75" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="fileLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="pathLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="19" max="-2" attributes="0"/>
<Component id="commentLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jScrollPane1" max="32767" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="okButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="cancelButton" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTextArea" name="commentTextArea">
<Properties>
<Property name="columns" type="int" value="20"/>
<Property name="lineWrap" type="boolean" value="true"/>
<Property name="rows" type="int" value="5"/>
<Property name="tabSize" type="int" value="4"/>
<Property name="wrapStyleWord" type="boolean" value="true"/>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JButton" name="okButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/Bundle.properties" key="CentralRepoCommentDialog.okButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="okButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="cancelButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/Bundle.properties" key="CentralRepoCommentDialog.cancelButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cancelButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="fileLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/Bundle.properties" key="CentralRepoCommentDialog.fileLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="pathLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/Bundle.properties" key="CentralRepoCommentDialog.pathLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="commentLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/Bundle.properties" key="CentralRepoCommentDialog.commentLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Form>
@@ -0,0 +1,187 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.centralrepository;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
/**
* Dialog to allow Central Repository file instance comments to be added and
* modified.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class CentralRepoCommentDialog extends javax.swing.JDialog {
private final CorrelationAttribute correlationAttribute;
private boolean commentUpdated = false;
/**
* Create an instance.
*
* @param correlationAttribute The correlation attribute to be modified.
* @param title The title to assign the dialog.
*/
CentralRepoCommentDialog(CorrelationAttribute correlationAttribute, String title) {
super(WindowManager.getDefault().getMainWindow(), title);
initComponents();
CorrelationAttributeInstance instance = correlationAttribute.getInstances().get(0);
pathLabel.setText(instance.getFilePath());
commentTextArea.setText(instance.getComment());
this.correlationAttribute = correlationAttribute;
}
/**
* Display the dialog.
*/
void display() {
setModal(true);
setSize(getPreferredSize());
setLocationRelativeTo(this.getParent());
setAlwaysOnTop(false);
pack();
setVisible(true);
}
/**
* Has the comment been updated?
*
* @return True if the comment has been updated; otherwise false.
*/
boolean isCommentUpdated() {
return commentUpdated;
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jScrollPane1 = new javax.swing.JScrollPane();
commentTextArea = new javax.swing.JTextArea();
okButton = new javax.swing.JButton();
cancelButton = new javax.swing.JButton();
fileLabel = new javax.swing.JLabel();
pathLabel = new javax.swing.JLabel();
commentLabel = new javax.swing.JLabel();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setSize(getPreferredSize());
commentTextArea.setColumns(20);
commentTextArea.setLineWrap(true);
commentTextArea.setRows(5);
commentTextArea.setTabSize(4);
commentTextArea.setWrapStyleWord(true);
jScrollPane1.setViewportView(commentTextArea);
org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(CentralRepoCommentDialog.class, "CentralRepoCommentDialog.okButton.text")); // NOI18N
okButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
okButtonActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(CentralRepoCommentDialog.class, "CentralRepoCommentDialog.cancelButton.text")); // NOI18N
cancelButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cancelButtonActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(fileLabel, org.openide.util.NbBundle.getMessage(CentralRepoCommentDialog.class, "CentralRepoCommentDialog.fileLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(pathLabel, org.openide.util.NbBundle.getMessage(CentralRepoCommentDialog.class, "CentralRepoCommentDialog.pathLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(commentLabel, org.openide.util.NbBundle.getMessage(CentralRepoCommentDialog.class, "CentralRepoCommentDialog.commentLabel.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 500, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(fileLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(pathLabel))
.addComponent(commentLabel))
.addGap(0, 451, Short.MAX_VALUE))
.addGroup(layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addComponent(okButton, javax.swing.GroupLayout.PREFERRED_SIZE, 75, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cancelButton, javax.swing.GroupLayout.PREFERRED_SIZE, 75, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(fileLabel)
.addComponent(pathLabel))
.addGap(19, 19, 19)
.addComponent(commentLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jScrollPane1)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(okButton)
.addComponent(cancelButton))
.addContainerGap())
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
dispose();
}//GEN-LAST:event_cancelButtonActionPerformed
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
String comment = commentTextArea.getText();
correlationAttribute.getInstances().get(0).setComment(comment);
commentUpdated = true;
dispose();
}//GEN-LAST:event_okButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton cancelButton;
private javax.swing.JLabel commentLabel;
private javax.swing.JTextArea commentTextArea;
private javax.swing.JLabel fileLabel;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JButton okButton;
private javax.swing.JLabel pathLabel;
// End of variables declaration//GEN-END:variables
}
@@ -3,3 +3,4 @@ DataContentViewerOtherCases.showCaseDetailsMenuItem.text=Show Case Details
DataContentViewerOtherCases.table.toolTip.text=Click column name to sort. Right-click on the table for more options.
DataContentViewerOtherCases.exportToCSVMenuItem.text=Export Selected Rows to CSV
DataContentViewerOtherCases.showCommonalityMenuItem.text=Show Frequency
DataContentViewerOtherCases.addCommentMenuItem.text=Add/Edit Comment
@@ -3,6 +3,9 @@
<Form version="1.6" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<NonVisualComponents>
<Container class="javax.swing.JPopupMenu" name="rightClickPopupMenu">
<Events>
<EventHandler event="popupMenuWillBecomeVisible" listener="javax.swing.event.PopupMenuListener" parameters="javax.swing.event.PopupMenuEvent" handler="rightClickPopupMenuPopupMenuWillBecomeVisible"/>
</Events>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout">
<Property name="useNullLayout" type="boolean" value="true"/>
@@ -36,6 +39,13 @@
</Property>
</Properties>
</MenuItem>
<MenuItem class="javax.swing.JMenuItem" name="addCommentMenuItem">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/contentviewer/Bundle.properties" key="DataContentViewerOtherCases.addCommentMenuItem.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</MenuItem>
</SubComponents>
</Container>
<Component class="javax.swing.JFileChooser" name="CSVFileChooser">
@@ -18,9 +18,7 @@
*/
package org.sleuthkit.autopsy.centralrepository.contentviewer;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedWriter;
@@ -37,30 +35,22 @@ import java.util.Objects;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
import java.util.stream.Collectors;
import javax.swing.GroupLayout;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import static javax.swing.JOptionPane.DEFAULT_OPTION;
import static javax.swing.JOptionPane.PLAIN_MESSAGE;
import static javax.swing.JOptionPane.ERROR_MESSAGE;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.LayoutStyle;
import javax.swing.ListSelectionModel;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import org.openide.awt.Mnemonics;
import org.openide.nodes.Node;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.centralrepository.AddEditCentralRepoCommentAction;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
@@ -76,6 +66,7 @@ import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskException;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskDataException;
@@ -88,8 +79,8 @@ import org.sleuthkit.datamodel.TskDataException;
@Messages({"DataContentViewerOtherCases.title=Other Occurrences",
"DataContentViewerOtherCases.toolTip=Displays instances of the selected file/artifact from other occurrences.",})
public class DataContentViewerOtherCases extends JPanel implements DataContentViewer {
private final static Logger LOGGER = Logger.getLogger(DataContentViewerOtherCases.class.getName());
private final static Logger logger = Logger.getLogger(DataContentViewerOtherCases.class.getName());
private final DataContentViewerOtherCasesTableModel tableModel;
private final Collection<CorrelationAttribute> correlationAttributes;
@@ -123,10 +114,15 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
try {
saveToCSV();
} catch (NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
logger.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
}
} else if (jmi.equals(showCommonalityMenuItem)) {
showCommonalityDetails();
} else if (jmi.equals(addCommentMenuItem)) {
CorrelationAttribute selectedAttribute = (CorrelationAttribute) tableModel.getRow(otherCasesTable.getSelectedRow());
AddEditCentralRepoCommentAction action = AddEditCentralRepoCommentAction.createAddEditCommentAction(selectedAttribute);
action.addEditCentralRepoComment();
otherCasesTable.repaint();
}
}
};
@@ -135,6 +131,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
selectAllMenuItem.addActionListener(actList);
showCaseDetailsMenuItem.addActionListener(actList);
showCommonalityMenuItem.addActionListener(actList);
addCommentMenuItem.addActionListener(actList);
// Set background of every nth row as light grey.
TableCellRenderer renderer = new DataContentViewerOtherCasesTableCellRenderer();
@@ -150,7 +147,8 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
"DataContentViewerOtherCases.correlatedArtifacts.title=Attribute Frequency",
"DataContentViewerOtherCases.correlatedArtifacts.failed=Failed to get frequency details."})
/**
* Show how common the selected correlationAttributes are with details dialog.
* Show how common the selected correlationAttributes are with details
* dialog.
*/
private void showCommonalityDetails() {
if (correlationAttributes.isEmpty()) {
@@ -174,7 +172,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
Bundle.DataContentViewerOtherCases_correlatedArtifacts_title(),
DEFAULT_OPTION, PLAIN_MESSAGE);
} catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error getting commonality details.", ex);
logger.log(Level.SEVERE, "Error getting commonality details.", ex);
JOptionPane.showConfirmDialog(showCommonalityMenuItem,
Bundle.DataContentViewerOtherCases_correlatedArtifacts_failed(),
Bundle.DataContentViewerOtherCases_correlatedArtifacts_title(),
@@ -298,7 +296,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
}
} catch (IOException ex) {
LOGGER.log(Level.SEVERE, "Error writing selected rows to CSV.", ex);
logger.log(Level.SEVERE, "Error writing selected rows to CSV.", ex);
}
}
@@ -389,7 +387,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
try {
content = nodeBbArtifact.getSleuthkitCase().getContentById(nodeBbArtifact.getObjectID());
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error retrieving blackboard artifact", ex); // NON-NLS
logger.log(Level.SEVERE, "Error retrieving blackboard artifact", ex); // NON-NLS
return null;
}
@@ -435,20 +433,20 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
}
}
} catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error connecting to DB", ex); // NON-NLS
logger.log(Level.SEVERE, "Error connecting to DB", ex); // NON-NLS
}
} else {
try {
// If EamDb not enabled, get the Files default correlation type to allow Other Occurances to be enabled.
if(this.file != null) {
if (this.file != null) {
String md5 = this.file.getMd5Hash();
if(md5 != null && !md5.isEmpty()) {
ret.add(new CorrelationAttribute(CorrelationAttribute.getDefaultCorrelationTypes().get(0),md5));
if (md5 != null && !md5.isEmpty()) {
ret.add(new CorrelationAttribute(CorrelationAttribute.getDefaultCorrelationTypes().get(0), md5));
}
}
} catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error connecting to DB", ex); // NON-NLS
logger.log(Level.SEVERE, "Error connecting to DB", ex); // NON-NLS
}
}
@@ -456,34 +454,36 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
}
/**
* Query the db for artifact instances from other cases correlated to the
* given central repository artifact. Will not show instances from the same
* datasource / device
* Query the database for artifact instances from other cases correlated to
* the given central repository artifact. Instances from the same datasource
* / device will also be included.
*
* @param corAttr CorrelationAttribute to query for
* @param corAttr CorrelationAttribute to query for
* @param dataSourceName Data source to filter results
* @param deviceId Device Id to filter results
* @param deviceId Device Id to filter results
*
* @return A collection of correlated artifact instances from other cases
* @return A collection of correlated artifact instances
*/
private Map<UniquePathKey,CorrelationAttributeInstance> getCorrelatedInstances(CorrelationAttribute corAttr, String dataSourceName, String deviceId) {
private Map<UniquePathKey, CorrelationAttributeInstance> getCorrelatedInstances(CorrelationAttribute corAttr, String dataSourceName, String deviceId) {
// @@@ Check exception
try {
final Case openCase = Case.getCurrentCase();
String caseUUID = openCase.getName();
HashMap<UniquePathKey,CorrelationAttributeInstance> artifactInstances = new HashMap<>();
String filePath = (file.getParentPath() + file.getName()).toLowerCase();
HashMap<UniquePathKey, CorrelationAttributeInstance> artifactInstances = new HashMap<>();
if (EamDb.isEnabled()) {
EamDb dbManager = EamDb.getInstance();
artifactInstances.putAll(dbManager.getArtifactInstancesByTypeValue(corAttr.getCorrelationType(), corAttr.getCorrelationValue()).stream()
.filter(artifactInstance -> !artifactInstance.getCorrelationCase().getCaseUUID().equals(caseUUID)
.filter(artifactInstance -> !artifactInstance.getFilePath().equals(filePath)
|| !artifactInstance.getCorrelationCase().getCaseUUID().equals(caseUUID)
|| !artifactInstance.getCorrelationDataSource().getName().equals(dataSourceName)
|| !artifactInstance.getCorrelationDataSource().getDeviceID().equals(deviceId))
.collect(Collectors.toMap(correlationAttr -> new UniquePathKey(correlationAttr.getCorrelationDataSource().getDeviceID(), correlationAttr.getFilePath()),
correlationAttr -> correlationAttr)));
}
if (corAttr.getCorrelationType().getDisplayName().equals("Files")) {
if (corAttr.getCorrelationType().getDisplayName().equals("Files")) {
List<AbstractFile> caseDbFiles = addCaseDbMatches(corAttr, openCase);
for (AbstractFile caseDbFile : caseDbFiles) {
addOrUpdateAttributeInstance(openCase, artifactInstances, caseDbFile);
@@ -492,13 +492,13 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
return artifactInstances;
} catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error getting artifact instances from database.", ex); // NON-NLS
logger.log(Level.SEVERE, "Error getting artifact instances from database.", ex); // NON-NLS
} catch (NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
logger.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
} catch (TskCoreException ex) {
// do nothing.
// @@@ Review this behavior
LOGGER.log(Level.SEVERE, "Exception while querying open case.", ex); // NON-NLS
logger.log(Level.SEVERE, "Exception while querying open case.", ex); // NON-NLS
}
return new HashMap<>(0);
@@ -523,15 +523,16 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
/**
* Adds the file to the artifactInstances map if it does not already exist
*
* @param autopsyCase
*
* @param autopsyCase
* @param artifactInstances
* @param newFile
*
* @throws TskCoreException
* @throws EamDbException
* @throws EamDbException
*/
private void addOrUpdateAttributeInstance(final Case autopsyCase, Map<UniquePathKey,CorrelationAttributeInstance> artifactInstances, AbstractFile newFile) throws TskCoreException, EamDbException {
private void addOrUpdateAttributeInstance(final Case autopsyCase, Map<UniquePathKey, CorrelationAttributeInstance> artifactInstances, AbstractFile newFile) throws TskCoreException, EamDbException {
// figure out if the casedb file is known via either hash or tags
TskData.FileKnown localKnown = newFile.getKnown();
@@ -552,26 +553,25 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
try {
deviceId = autopsyCase.getSleuthkitCase().getDataSource(newFile.getDataSource().getId()).getDeviceId();
} catch (TskDataException | TskCoreException ex) {
LOGGER.log(Level.WARNING, "Error getting data source info: " + ex);
logger.log(Level.WARNING, "Error getting data source info: {0}", ex);
return;
}
UniquePathKey uniquePathKey = new UniquePathKey(deviceId, filePath);
// double check that the CR version is BAD if the caseDB version is BAD.
if (artifactInstances.containsKey(uniquePathKey)) {
if (localKnown == TskData.FileKnown.BAD) {
CorrelationAttributeInstance prevInstance = artifactInstances.get(uniquePathKey);
prevInstance.setKnownStatus(localKnown);
}
}
// add the data from the case DB by pushing data into CorrelationAttributeInstance class
} // add the data from the case DB by pushing data into CorrelationAttributeInstance class
else {
// NOTE: If we are in here, it is likely because CR is not enabled. So, we cannot rely
// on any of the methods that query the DB.
CorrelationCase correlationCase = new CorrelationCase(autopsyCase.getName(), autopsyCase.getDisplayName());
CorrelationDataSource correlationDataSource = CorrelationDataSource.fromTSKDataSource(correlationCase, newFile.getDataSource());
CorrelationAttributeInstance caseDbInstance = new CorrelationAttributeInstance(correlationCase, correlationDataSource, filePath, "", localKnown);
artifactInstances.put(uniquePathKey, caseDbInstance);
}
@@ -583,14 +583,14 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
// Is supported if this node
// has correlatable content (File, BlackboardArtifact) OR
// other common files across datasources.
if(EamDb.isEnabled()){
if (EamDb.isEnabled()) {
return this.file != null
&& this.file.getSize() > 0
&& !getCorrelationAttributesFromNode(node).isEmpty();
} else{
&& this.file.getSize() > 0
&& !getCorrelationAttributesFromNode(node).isEmpty();
} else {
return this.file != null
&& this.file.getSize() > 0;
&& this.file.getSize() > 0;
}
}
@@ -646,7 +646,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
newCeArtifact.addInstance(corAttrInstance);
tableModel.addEamArtifact(newCeArtifact);
} catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error creating correlation attribute", ex);
logger.log(Level.SEVERE, "Error creating correlation attribute", ex);
}
});
}
@@ -690,127 +690,165 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
rightClickPopupMenu = new JPopupMenu();
selectAllMenuItem = new JMenuItem();
exportToCSVMenuItem = new JMenuItem();
showCaseDetailsMenuItem = new JMenuItem();
showCommonalityMenuItem = new JMenuItem();
CSVFileChooser = new JFileChooser();
otherCasesPanel = new JPanel();
tableContainerPanel = new JPanel();
tableScrollPane = new JScrollPane();
otherCasesTable = new JTable();
tableStatusPanel = new JPanel();
tableStatusPanelLabel = new JLabel();
rightClickPopupMenu = new javax.swing.JPopupMenu();
selectAllMenuItem = new javax.swing.JMenuItem();
exportToCSVMenuItem = new javax.swing.JMenuItem();
showCaseDetailsMenuItem = new javax.swing.JMenuItem();
showCommonalityMenuItem = new javax.swing.JMenuItem();
addCommentMenuItem = new javax.swing.JMenuItem();
CSVFileChooser = new javax.swing.JFileChooser();
otherCasesPanel = new javax.swing.JPanel();
tableContainerPanel = new javax.swing.JPanel();
tableScrollPane = new javax.swing.JScrollPane();
otherCasesTable = new javax.swing.JTable();
tableStatusPanel = new javax.swing.JPanel();
tableStatusPanelLabel = new javax.swing.JLabel();
Mnemonics.setLocalizedText(selectAllMenuItem, NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.selectAllMenuItem.text")); // NOI18N
rightClickPopupMenu.addPopupMenuListener(new javax.swing.event.PopupMenuListener() {
public void popupMenuCanceled(javax.swing.event.PopupMenuEvent evt) {
}
public void popupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent evt) {
}
public void popupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent evt) {
rightClickPopupMenuPopupMenuWillBecomeVisible(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(selectAllMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.selectAllMenuItem.text")); // NOI18N
rightClickPopupMenu.add(selectAllMenuItem);
Mnemonics.setLocalizedText(exportToCSVMenuItem, NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.exportToCSVMenuItem.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(exportToCSVMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.exportToCSVMenuItem.text")); // NOI18N
rightClickPopupMenu.add(exportToCSVMenuItem);
Mnemonics.setLocalizedText(showCaseDetailsMenuItem, NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.showCaseDetailsMenuItem.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(showCaseDetailsMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.showCaseDetailsMenuItem.text")); // NOI18N
rightClickPopupMenu.add(showCaseDetailsMenuItem);
Mnemonics.setLocalizedText(showCommonalityMenuItem, NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.showCommonalityMenuItem.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(showCommonalityMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.showCommonalityMenuItem.text")); // NOI18N
rightClickPopupMenu.add(showCommonalityMenuItem);
setMinimumSize(new Dimension(1500, 10));
org.openide.awt.Mnemonics.setLocalizedText(addCommentMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.addCommentMenuItem.text")); // NOI18N
rightClickPopupMenu.add(addCommentMenuItem);
setMinimumSize(new java.awt.Dimension(1500, 10));
setOpaque(false);
setPreferredSize(new Dimension(1500, 44));
setPreferredSize(new java.awt.Dimension(1500, 44));
otherCasesPanel.setPreferredSize(new Dimension(1500, 144));
otherCasesPanel.setPreferredSize(new java.awt.Dimension(1500, 144));
tableContainerPanel.setPreferredSize(new Dimension(1500, 63));
tableContainerPanel.setPreferredSize(new java.awt.Dimension(1500, 63));
tableScrollPane.setPreferredSize(new Dimension(1500, 30));
tableScrollPane.setPreferredSize(new java.awt.Dimension(1500, 30));
otherCasesTable.setAutoCreateRowSorter(true);
otherCasesTable.setModel(tableModel);
otherCasesTable.setToolTipText(NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.table.toolTip.text")); // NOI18N
otherCasesTable.setToolTipText(org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.table.toolTip.text")); // NOI18N
otherCasesTable.setComponentPopupMenu(rightClickPopupMenu);
otherCasesTable.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
otherCasesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_INTERVAL_SELECTION);
tableScrollPane.setViewportView(otherCasesTable);
tableStatusPanel.setPreferredSize(new Dimension(1500, 16));
tableStatusPanel.setPreferredSize(new java.awt.Dimension(1500, 16));
tableStatusPanelLabel.setForeground(new Color(255, 0, 51));
tableStatusPanelLabel.setForeground(new java.awt.Color(255, 0, 51));
GroupLayout tableStatusPanelLayout = new GroupLayout(tableStatusPanel);
javax.swing.GroupLayout tableStatusPanelLayout = new javax.swing.GroupLayout(tableStatusPanel);
tableStatusPanel.setLayout(tableStatusPanelLayout);
tableStatusPanelLayout.setHorizontalGroup(tableStatusPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
tableStatusPanelLayout.setHorizontalGroup(
tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 0, Short.MAX_VALUE)
.addGroup(tableStatusPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(tableStatusPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(tableStatusPanelLabel, GroupLayout.DEFAULT_SIZE, 780, Short.MAX_VALUE)
.addComponent(tableStatusPanelLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 780, Short.MAX_VALUE)
.addContainerGap()))
);
tableStatusPanelLayout.setVerticalGroup(tableStatusPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
tableStatusPanelLayout.setVerticalGroup(
tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 16, Short.MAX_VALUE)
.addGroup(tableStatusPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(tableStatusPanelLayout.createSequentialGroup()
.addComponent(tableStatusPanelLabel, GroupLayout.PREFERRED_SIZE, 16, GroupLayout.PREFERRED_SIZE)
.addComponent(tableStatusPanelLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, Short.MAX_VALUE)))
);
GroupLayout tableContainerPanelLayout = new GroupLayout(tableContainerPanel);
javax.swing.GroupLayout tableContainerPanelLayout = new javax.swing.GroupLayout(tableContainerPanel);
tableContainerPanel.setLayout(tableContainerPanelLayout);
tableContainerPanelLayout.setHorizontalGroup(tableContainerPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(tableScrollPane, GroupLayout.Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(tableStatusPanel, GroupLayout.Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
tableContainerPanelLayout.setHorizontalGroup(
tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(tableScrollPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(tableStatusPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
tableContainerPanelLayout.setVerticalGroup(tableContainerPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
tableContainerPanelLayout.setVerticalGroup(
tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(tableContainerPanelLayout.createSequentialGroup()
.addComponent(tableScrollPane, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addComponent(tableStatusPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addComponent(tableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(tableStatusPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
);
GroupLayout otherCasesPanelLayout = new GroupLayout(otherCasesPanel);
javax.swing.GroupLayout otherCasesPanelLayout = new javax.swing.GroupLayout(otherCasesPanel);
otherCasesPanel.setLayout(otherCasesPanelLayout);
otherCasesPanelLayout.setHorizontalGroup(otherCasesPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
otherCasesPanelLayout.setHorizontalGroup(
otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 1500, Short.MAX_VALUE)
.addGroup(otherCasesPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(tableContainerPanel, GroupLayout.Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGroup(otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(tableContainerPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
otherCasesPanelLayout.setVerticalGroup(otherCasesPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
otherCasesPanelLayout.setVerticalGroup(
otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 60, Short.MAX_VALUE)
.addGroup(otherCasesPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(otherCasesPanelLayout.createSequentialGroup()
.addComponent(tableContainerPanel, GroupLayout.DEFAULT_SIZE, 60, Short.MAX_VALUE)
.addComponent(tableContainerPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 52, Short.MAX_VALUE)
.addGap(0, 0, 0)))
);
GroupLayout layout = new GroupLayout(this);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(otherCasesPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(otherCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
layout.setVerticalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(otherCasesPanel, GroupLayout.DEFAULT_SIZE, 60, Short.MAX_VALUE)
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(otherCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 52, Short.MAX_VALUE)
);
}// </editor-fold>//GEN-END:initComponents
private void rightClickPopupMenuPopupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent evt) {//GEN-FIRST:event_rightClickPopupMenuPopupMenuWillBecomeVisible
boolean addCommentMenuItemVisible = false;
if (EamDbUtil.useCentralRepo() && otherCasesTable.getSelectedRowCount() == 1) {
int rowIndex = otherCasesTable.getSelectedRow();
CorrelationAttribute selectedAttribute = (CorrelationAttribute) tableModel.getRow(rowIndex);
if (selectedAttribute.getInstances().get(0).isDatabaseInstance()
&& selectedAttribute.getCorrelationType().getId() == CorrelationAttribute.FILES_TYPE_ID) {
addCommentMenuItemVisible = true;
}
}
addCommentMenuItem.setVisible(addCommentMenuItemVisible);
}//GEN-LAST:event_rightClickPopupMenuPopupMenuWillBecomeVisible
// Variables declaration - do not modify//GEN-BEGIN:variables
private JFileChooser CSVFileChooser;
private JMenuItem exportToCSVMenuItem;
private JPanel otherCasesPanel;
private JTable otherCasesTable;
private JPopupMenu rightClickPopupMenu;
private JMenuItem selectAllMenuItem;
private JMenuItem showCaseDetailsMenuItem;
private JMenuItem showCommonalityMenuItem;
private JPanel tableContainerPanel;
private JScrollPane tableScrollPane;
private JPanel tableStatusPanel;
private JLabel tableStatusPanelLabel;
private javax.swing.JFileChooser CSVFileChooser;
private javax.swing.JMenuItem addCommentMenuItem;
private javax.swing.JMenuItem exportToCSVMenuItem;
private javax.swing.JPanel otherCasesPanel;
private javax.swing.JTable otherCasesTable;
private javax.swing.JPopupMenu rightClickPopupMenu;
private javax.swing.JMenuItem selectAllMenuItem;
private javax.swing.JMenuItem showCaseDetailsMenuItem;
private javax.swing.JMenuItem showCommonalityMenuItem;
private javax.swing.JPanel tableContainerPanel;
private javax.swing.JScrollPane tableScrollPane;
private javax.swing.JPanel tableStatusPanel;
private javax.swing.JLabel tableStatusPanelLabel;
// End of variables declaration//GEN-END:variables
/**
* Used as a key to ensure we eliminate duplicates from the result set by not overwriting CR correlation instances.
* Used as a key to ensure we eliminate duplicates from the result set by
* not overwriting CR correlation instances.
*/
static final class UniquePathKey {
File diff suppressed because it is too large Load Diff
@@ -1,7 +1,7 @@
/*
* Central Repository
*
* Copyright 2015-2017 Basis Technology Corp.
* Copyright 2015-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,8 +24,8 @@ import org.sleuthkit.datamodel.TskData;
/**
*
* Used to store details about a specific instance of a
* CorrelationAttribute. Includes its data source, path, etc.
* Used to store details about a specific instance of a CorrelationAttribute.
* Includes its data source, path, etc.
*
*/
@Messages({
@@ -43,13 +43,6 @@ public class CorrelationAttributeInstance implements Serializable {
private String comment;
private TskData.FileKnown knownStatus;
public CorrelationAttributeInstance(
CorrelationCase eamCase,
CorrelationDataSource eamDataSource
) throws EamDbException {
this(-1, eamCase, eamDataSource, "", null, TskData.FileKnown.UNKNOWN);
}
public CorrelationAttributeInstance(
CorrelationCase eamCase,
CorrelationDataSource eamDataSource,
@@ -58,14 +51,6 @@ public class CorrelationAttributeInstance implements Serializable {
this(-1, eamCase, eamDataSource, filePath, null, TskData.FileKnown.UNKNOWN);
}
public CorrelationAttributeInstance(
CorrelationCase eamCase,
CorrelationDataSource eamDataSource,
String filePath,
String comment
) throws EamDbException {
this(-1, eamCase, eamDataSource, filePath, comment, TskData.FileKnown.UNKNOWN);
}
public CorrelationAttributeInstance(
CorrelationCase eamCase,
@@ -85,10 +70,10 @@ public class CorrelationAttributeInstance implements Serializable {
String comment,
TskData.FileKnown knownStatus
) throws EamDbException {
if(filePath == null) {
if (filePath == null) {
throw new EamDbException("file path is null");
}
this.ID = ID;
this.correlationCase = eamCase;
this.correlationDataSource = eamDataSource;
@@ -117,6 +102,16 @@ public class CorrelationAttributeInstance implements Serializable {
+ this.getComment();
}
/**
* Is this a database instance?
*
* @return True if the instance ID is greater or equal to zero; otherwise
* false.
*/
public boolean isDatabaseInstance() {
return (ID >= 0);
}
/**
* @return the database ID
*/
@@ -160,9 +155,9 @@ public class CorrelationAttributeInstance implements Serializable {
}
/**
* Get this knownStatus. This only indicates whether an item has been
* tagged as notable and should never return KNOWN.
*
* Get this knownStatus. This only indicates whether an item has been tagged
* as notable and should never return KNOWN.
*
* @return BAD if the item has been tagged as notable, UNKNOWN otherwise
*/
public TskData.FileKnown getKnownStatus() {
@@ -170,10 +165,11 @@ public class CorrelationAttributeInstance implements Serializable {
}
/**
* Set the knownStatus. This only indicates whether an item has been
* tagged as notable and should never be set to KNOWN.
*
* @param knownStatus Should be BAD if the item is tagged as notable, UNKNOWN otherwise
* Set the knownStatus. This only indicates whether an item has been tagged
* as notable and should never be set to KNOWN.
*
* @param knownStatus Should be BAD if the item is tagged as notable,
* UNKNOWN otherwise
*/
public void setKnownStatus(TskData.FileKnown knownStatus) {
this.knownStatus = knownStatus;
@@ -40,15 +40,21 @@ public class CorrelationDataSource implements Serializable {
private final String name;
/**
*
* @param caseId
* @param deviceId
* @param name
* @param correlationCase CorrelationCase object data source is associated with. Must have been created by EamDB and have a valid ID.
* @param deviceId User specified case-specific ID
* @param name Display name of data source
*/
public CorrelationDataSource(int caseId, String deviceId, String name) {
this(caseId, -1, deviceId, name);
public CorrelationDataSource(CorrelationCase correlationCase, String deviceId, String name) {
this(correlationCase.getID(), -1, deviceId, name);
}
/**
*
* @param caseId Row ID for Case in DB
* @param dataSourceId Row ID for this data source in DB (or -1)
* @param deviceId User specified ID for device (unique per case)
* @param name User specified name
*/
CorrelationDataSource(int caseId,
int dataSourceId,
String deviceId,
@@ -84,7 +90,18 @@ public class CorrelationDataSource implements Serializable {
} catch (TskDataException | TskCoreException ex) {
throw new EamDbException("Error getting data source info: " + ex.getMessage());
}
return new CorrelationDataSource(correlationCase.getID(), -1, deviceId, dataSource.getName());
CorrelationDataSource correlationDataSource = null;
if (EamDbUtil.useCentralRepo()) {
correlationDataSource = EamDb.getInstance().getDataSource(correlationCase, deviceId);
}
if (correlationDataSource == null) {
correlationDataSource = new CorrelationDataSource(correlationCase, deviceId, dataSource.getName());
if (EamDbUtil.useCentralRepo()) {
EamDb.getInstance().newDataSource(correlationDataSource);
}
}
return correlationDataSource;
}
@Override
@@ -102,7 +119,7 @@ public class CorrelationDataSource implements Serializable {
/**
* Get the database row ID
*
* @return the ID
* @return the ID or -1 if unknown
*/
int getID() {
return dataSourceID;
@@ -39,7 +39,7 @@ import org.sleuthkit.datamodel.TskData;
public class EamArtifactUtil {
private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(EamArtifactUtil.class.getName());
private static final Logger logger = Logger.getLogger(EamArtifactUtil.class.getName());
public EamArtifactUtil() {
}
@@ -76,14 +76,14 @@ public class EamArtifactUtil {
// have switch based on artifact type
for (CorrelationAttribute.Type aType : EamDb.getInstance().getDefinedCorrelationTypes()) {
if ((checkEnabled && aType.isEnabled()) || !checkEnabled) {
CorrelationAttribute eamArtifact = EamArtifactUtil.getCorrelationAttributeFromBlackboardArtifact(aType, bbArtifact);
if (eamArtifact != null) {
eamArtifacts.add(eamArtifact);
CorrelationAttribute correlationAttribute = EamArtifactUtil.getCorrelationAttributeFromBlackboardArtifact(aType, bbArtifact);
if (correlationAttribute != null) {
eamArtifacts.add(correlationAttribute);
}
}
}
} catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error getting defined correlation types.", ex); // NON-NLS
logger.log(Level.SEVERE, "Error getting defined correlation types.", ex); // NON-NLS
return eamArtifacts;
}
@@ -115,10 +115,10 @@ public class EamArtifactUtil {
eamArtifact.addInstance(eamInstance);
}
} catch (TskCoreException | EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error creating artifact instance.", ex); // NON-NLS
logger.log(Level.SEVERE, "Error creating artifact instance.", ex); // NON-NLS
return eamArtifacts;
} catch (NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Case is closed.", ex); // NON-NLS
logger.log(Level.SEVERE, "Case is closed.", ex); // NON-NLS
return eamArtifacts;
}
}
@@ -136,7 +136,7 @@ public class EamArtifactUtil {
* @return the new EamArtifact, or null if one was not created because
* bbArtifact did not contain the needed data
*/
private static CorrelationAttribute getCorrelationAttributeFromBlackboardArtifact(CorrelationAttribute.Type correlationType,
private static CorrelationAttribute getCorrelationAttributeFromBlackboardArtifact(CorrelationAttribute.Type correlationType,
BlackboardArtifact bbArtifact) throws EamDbException {
String value = null;
int artifactTypeID = bbArtifact.getArtifactTypeID();
@@ -202,10 +202,10 @@ public class EamArtifactUtil {
}
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error getting attribute while getting type from BlackboardArtifact.", ex); // NON-NLS
logger.log(Level.SEVERE, "Error getting attribute while getting type from BlackboardArtifact.", ex); // NON-NLS
return null;
} catch (NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
} catch (NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
return null;
}
@@ -216,6 +216,45 @@ public class EamArtifactUtil {
}
}
/**
* Retrieve CorrelationAttribute from the given Content.
*
* @param content The content object
*
* @return The new CorrelationAttribute, or null if retrieval failed.
*/
public static CorrelationAttribute getCorrelationAttributeFromContent(Content content) {
if (!(content instanceof AbstractFile)) {
return null;
}
final AbstractFile file = (AbstractFile) content;
if (!isSupportedAbstractFileType(file)) {
return null;
}
CorrelationAttribute correlationAttribute = null;
try {
CorrelationAttribute.Type type = EamDb.getInstance().getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID);
CorrelationCase correlationCase = EamDb.getInstance().getCase(Case.getCurrentCaseThrows());
if (null == correlationCase) {
correlationCase = EamDb.getInstance().newCase(Case.getCurrentCaseThrows());
}
CorrelationDataSource correlationDataSource = CorrelationDataSource.fromTSKDataSource(correlationCase, file.getDataSource());
String value = file.getMd5Hash();
String filePath = (file.getParentPath() + file.getName()).toLowerCase();
correlationAttribute = EamDb.getInstance().getCorrelationAttribute(type, correlationCase, correlationDataSource, value, filePath);
} catch (TskCoreException | EamDbException | NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "Error retrieving correlation attribute.", ex);
}
return correlationAttribute;
}
/**
* Create an EamArtifact from the given Content. Will return null if an
* artifact can not be created - this is not necessarily an error case, it
@@ -225,7 +264,7 @@ public class EamArtifactUtil {
*
* Does not add the artifact to the database.
*
* @param content The content object
* @param content The content object
*
* @return The new EamArtifact or null if creation failed
*/
@@ -237,7 +276,7 @@ public class EamArtifactUtil {
final AbstractFile af = (AbstractFile) content;
if (!isValidCentralRepoFile(af)) {
if (!isSupportedAbstractFileType(af)) {
return null;
}
@@ -262,7 +301,7 @@ public class EamArtifactUtil {
eamArtifact.addInstance(cei);
return eamArtifact;
} catch (TskCoreException | EamDbException | NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Error making correlation attribute.", ex);
logger.log(Level.SEVERE, "Error making correlation attribute.", ex);
return null;
}
}
@@ -271,21 +310,17 @@ public class EamArtifactUtil {
* Check whether the given abstract file should be processed for the central
* repository.
*
* @param af The file to test
* @param file The file to test
*
* @return true if the file should be added to the central repo, false
* otherwise
*/
public static boolean isValidCentralRepoFile(AbstractFile af) {
if (af == null) {
public static boolean isSupportedAbstractFileType(AbstractFile file) {
if (file == null) {
return false;
}
if (af.getKnown() == TskData.FileKnown.KNOWN) {
return false;
}
switch (af.getType()) {
switch (file.getType()) {
case UNALLOC_BLOCKS:
case UNUSED_BLOCKS:
case SLACK:
@@ -297,9 +332,9 @@ public class EamArtifactUtil {
case LOCAL:
return true;
case FS:
return af.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC);
return file.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC);
default:
LOGGER.log(Level.WARNING, "Unexpected file type {0}", af.getType().getName());
logger.log(Level.WARNING, "Unexpected file type {0}", file.getType().getName());
return false;
}
}
@@ -1,7 +1,7 @@
/*
* Central Repository
*
* Copyright 2015-2017 Basis Technology Corp.
* Copyright 2015-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -34,7 +34,8 @@ public interface EamDb {
public static final int SCHEMA_VERSION = 1;
public static final CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION
= new CaseDbSchemaVersionNumber(1, 1);
/**
* Get the instance
*
@@ -103,7 +104,7 @@ public interface EamDb {
/**
* Add a new name/value pair in the db_info table.
*
* @param name Key to set
* @param name Key to set
* @param value Value to set
*
* @throws EamDbException
@@ -124,7 +125,7 @@ public interface EamDb {
/**
* Update the value for a name in the name/value db_info table.
*
* @param name Name to find
* @param name Name to find
* @param value Value to assign to name.
*
* @throws EamDbException
@@ -158,7 +159,9 @@ public interface EamDb {
* Retrieves Central Repo case based on an Autopsy Case
*
* @param autopsyCase Autopsy case to find corresponding CR case for
*
* @return CR Case
*
* @throws EamDbException
*/
CorrelationCase getCase(Case autopsyCase) throws EamDbException;
@@ -189,8 +192,8 @@ public interface EamDb {
/**
* Retrieves Data Source details based on data source device ID
*
* @param correlationCase the current CorrelationCase used for ensuring
* uniqueness of DataSource
* @param correlationCase the current CorrelationCase used for ensuring
* uniqueness of DataSource
* @param dataSourceDeviceId the data source device ID number
*
* @return The data source
@@ -227,7 +230,7 @@ public interface EamDb {
* Retrieves eamArtifact instances from the database that are associated
* with the aType and filePath
*
* @param aType EamArtifact.Type to search for
* @param aType EamArtifact.Type to search for
* @param filePath File path to search for
*
* @return List of 0 or more EamArtifactInstances
@@ -244,7 +247,7 @@ public interface EamDb {
* @param value Value to search for
*
* @return Number of artifact instances having ArtifactType and
* ArtifactValue.
* ArtifactValue.
*/
Long getCountArtifactInstancesByTypeValue(CorrelationAttribute.Type aType, String value) throws EamDbException;
@@ -281,11 +284,11 @@ public interface EamDb {
* associated with the caseDisplayName and dataSource of the given
* eamArtifact instance.
*
* @param caseUUID Case ID to search for
* @param caseUUID Case ID to search for
* @param dataSourceID Data source ID to search for
*
* @return Number of artifact instances having caseDisplayName and
* dataSource
* dataSource
*/
Long getCountArtifactInstancesByCaseDataSource(String caseUUID, String dataSourceID) throws EamDbException;
@@ -309,6 +312,34 @@ public interface EamDb {
*/
void bulkInsertCases(List<CorrelationCase> cases) throws EamDbException;
/**
* Update a correlation attribute instance comment in the database with that
* in the associated CorrelationAttribute object.
*
* @param eamArtifact The correlation attribute whose database instance will
* be updated.
*
* @throws EamDbException
*/
void updateAttributeInstanceComment(CorrelationAttribute eamArtifact) throws EamDbException;
/**
* Find a correlation attribute in the Central Repository database given the
* instance type, case, data source, value, and file path.
*
* @param type The type of instance.
* @param correlationCase The case tied to the instance.
* @param correlationDataSource The data source tied to the instance.
* @param value The value tied to the instance.
* @param filePath The file path tied to the instance.
*
* @return The correlation attribute if it exists; otherwise null.
*
* @throws EamDbException
*/
CorrelationAttribute getCorrelationAttribute(CorrelationAttribute.Type type, CorrelationCase correlationCase,
CorrelationDataSource correlationDataSource, String value, String filePath) throws EamDbException;
/**
* Sets an eamArtifact instance to the given known status. If eamArtifact
* exists, it is updated. If eamArtifact does not exist nothing happens
@@ -329,6 +360,15 @@ public interface EamDb {
*/
List<CorrelationAttributeInstance> getArtifactInstancesKnownBad(CorrelationAttribute.Type aType, String value) throws EamDbException;
/**
* Gets list of matching eamArtifact instances that have knownStatus =
* "Bad".
*
* @param aType EamArtifact.Type to search for
* @return List with 0 or more matching eamArtifact instances.
* @throws EamDbException
*/
List<CorrelationAttributeInstance> getArtifactInstancesKnownBad(CorrelationAttribute.Type aType) throws EamDbException;
/**
* Count matching eamArtifacts instances that have knownStatus = "Bad".
*
@@ -347,7 +387,7 @@ public interface EamDb {
* @param value Value to search for
*
* @return List of cases containing this artifact with instances marked as
* bad
* bad
*
* @throws EamDbException
*/
@@ -357,6 +397,7 @@ public interface EamDb {
* Remove a reference set and all values contained in it.
*
* @param referenceSetID
*
* @throws EamDbException
*/
public void deleteReferenceSet(int referenceSetID) throws EamDbException;
@@ -369,7 +410,9 @@ public interface EamDb {
* @param referenceSetID
* @param referenceSetName
* @param version
*
* @return true if a matching entry exists in the central repository
*
* @throws EamDbException
*/
public boolean referenceSetIsValid(int referenceSetID, String referenceSetName, String version) throws EamDbException;
@@ -381,7 +424,9 @@ public interface EamDb {
*
* @param referenceSetName
* @param version
*
* @return true if a matching set is found
*
* @throws EamDbException
*/
public boolean referenceSetExists(String referenceSetName, String version) throws EamDbException;
@@ -392,7 +437,9 @@ public interface EamDb {
*
* @param hash
* @param referenceSetID
*
* @return true if the hash is found in the reference set
*
* @throws EamDbException
*/
public boolean isFileHashInReferenceSet(String hash, int referenceSetID) throws EamDbException;
@@ -403,6 +450,7 @@ public interface EamDb {
* @param value
* @param referenceSetID
* @param correlationTypeID
*
* @return true if the hash is found in the reference set
*/
public boolean isValueInReferenceSet(String value, int referenceSetID, int correlationTypeID) throws EamDbException;
@@ -422,11 +470,11 @@ public interface EamDb {
*
* @param eamOrg The organization to add
*
* @return the Organization ID of the newly created organization.
* @return The organization with the org ID set.
*
* @throws EamDbException
*/
long newOrganization(EamOrganization eamOrg) throws EamDbException;
EamOrganization newOrganization(EamOrganization eamOrg) throws EamDbException;
/**
* Get all organizations
@@ -452,7 +500,9 @@ public interface EamDb {
* Get the organization associated with the given reference set.
*
* @param referenceSetID ID of the reference set
*
* @return The organization object
*
* @throws EamDbException
*/
EamOrganization getReferenceSetOrganization(int referenceSetID) throws EamDbException;
@@ -461,7 +511,7 @@ public interface EamDb {
* Update an existing organization.
*
* @param updatedOrganization the values the Organization with the same ID
* will be updated to in the database.
* will be updated to in the database.
*
* @throws EamDbException
*/
@@ -502,7 +552,7 @@ public interface EamDb {
* Get all reference sets
*
* @param correlationType Type of sets to return
*
*
* @return List of all reference sets in the central repository
*
* @throws EamDbException
@@ -513,7 +563,8 @@ public interface EamDb {
* Add a new reference instance
*
* @param eamGlobalFileInstance The reference instance to add
* @param correlationType Correlation Type that this Reference Instance is
* @param correlationType Correlation Type that this Reference
* Instance is
*
* @throws EamDbException
*/
@@ -523,8 +574,8 @@ public interface EamDb {
* Insert the bulk collection of Global File Instances
*
* @param globalInstances a Set of EamGlobalFileInstances to insert into the
* db.
* @param contentType the Type of the global instances
* db.
* @param contentType the Type of the global instances
*
* @throws EamDbException
*/
@@ -533,7 +584,7 @@ public interface EamDb {
/**
* Get all reference entries having a given correlation type and value
*
* @param aType Type to use for matching
* @param aType Type to use for matching
* @param aValue Value to use for matching
*
* @return List of all global file instances with a type and value
@@ -558,7 +609,7 @@ public interface EamDb {
* used to correlate artifacts.
*
* @return List of EamArtifact.Type's. If none are defined in the database,
* the default list will be returned.
* the default list will be returned.
*
* @throws EamDbException
*/
@@ -569,7 +620,7 @@ public interface EamDb {
* artifacts.
*
* @return List of enabled EamArtifact.Type's. If none are defined in the
* database, the default list will be returned.
* database, the default list will be returned.
*
* @throws EamDbException
*/
@@ -580,7 +631,7 @@ public interface EamDb {
* correlate artifacts.
*
* @return List of supported EamArtifact.Type's. If none are defined in the
* database, the default list will be returned.
* database, the default list will be returned.
*
* @throws EamDbException
*/
@@ -620,8 +671,18 @@ public interface EamDb {
* (meaning the database is in use).
*
* @return the lock, or null if locking is not supported
*
* @throws EamDbException if the coordination service is running but we fail
* to get the lock
* to get the lock
*/
public CoordinationService.Lock getExclusiveMultiUserDbLock() throws EamDbException;
/**
* Process the Artifact instance in the EamDb
*
* @param type EamArtifact.Type to search for
* @param instanceTableCallback callback to process the instance
* @throws EamDbException
*/
void processInstanceTable(CorrelationAttribute.Type type, InstanceTableCallback instanceTableCallback) throws EamDbException;
}
@@ -42,18 +42,18 @@ public class EamDbUtil {
private static final String DEFAULT_ORG_NAME = "Not Specified";
/**
* Close the prepared statement.
* Close the statement.
*
* @param preparedStatement
* @param statement The statement to be closed.
*
* @throws EamDbException
*/
public static void closePreparedStatement(PreparedStatement preparedStatement) {
if (null != preparedStatement) {
public static void closeStatement(Statement statement) {
if (null != statement) {
try {
preparedStatement.close();
statement.close();
} catch (SQLException ex) {
LOGGER.log(Level.SEVERE, "Error closing PreparedStatement.", ex);
LOGGER.log(Level.SEVERE, "Error closing Statement.", ex);
}
}
}
@@ -361,4 +361,18 @@ public class EamDbUtil {
return "reference_" + type.getDbTableName();
}
/**
* Close the prepared statement.
*
* @param preparedStatement The prepared statement to be closed.
*
* @deprecated Use closeStatement() instead.
*
* @throws EamDbException
*/
@Deprecated
public static void closePreparedStatement(PreparedStatement preparedStatement) {
closeStatement(preparedStatement);
}
}
@@ -29,7 +29,7 @@ public class EamOrganization {
private String pocEmail;
private String pocPhone;
public EamOrganization(
EamOrganization(
int orgID,
String name,
String pocName,
@@ -84,7 +84,7 @@ public class EamOrganization {
/**
* @param orgID the orgID to set
*/
public void setOrgID(int orgID) {
void setOrgID(int orgID) {
this.orgID = orgID;
}
@@ -0,0 +1,109 @@
/*
* Central Repository
*
* Copyright 2015-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.centralrepository.datamodel;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* CallBack Interface to process attribute instance Table. Used in EamDb.processInstanceTable
* is called only once. The implementation of this method needs to call resultset.next to
* loop through each row of attribute instance table.
*/
public interface InstanceTableCallback {
/**
* Process the attribute instance
*
* @param resultSet attribute instance table.
*/
void process(ResultSet resultSet);
/**
*
* @param resultSet attribute instance table
* @return ID of the instance
* @throws SQLException
*/
static int getId(ResultSet resultSet) throws SQLException{
return resultSet.getInt("id");
}
/**
*
* @param resultSet attribute instance table
* @return Case ID of a given instance
* @throws SQLException
*/
static int getCaseId(ResultSet resultSet) throws SQLException {
return resultSet.getInt("case_id");
}
/**
*
* @param resultSet attribute instance table
* @return Data source id of a particular instance
* @throws SQLException
*/
static int getDataSourceId(ResultSet resultSet) throws SQLException {
return resultSet.getInt("data_source_id");
}
/**
*
* @param resultSet attribute instance table
* @return md5 hash value of the instance
* @throws SQLException
*/
static String getValue(ResultSet resultSet) throws SQLException {
return resultSet.getString("value");
}
/**
*
* @param resultSet attribute instance table
* @return file path of the instance
* @throws SQLException
*/
static String getFilePath(ResultSet resultSet) throws SQLException {
return resultSet.getString("file_path");
}
/**
*
* @param resultSet attribute instance table
* @return status integer based on whether instance is marked notable or not
* @throws SQLException
*/
static int getKnownStatus(ResultSet resultSet) throws SQLException {
return resultSet.getInt("known_status");
}
/**
*
* @param resultSet attribute instance table
* @return previous comment made for the instance
* @throws SQLException
*/
static String getComment(ResultSet resultSet) throws SQLException {
return resultSet.getString("comment");
}
}
@@ -24,8 +24,6 @@ import java.sql.Statement;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import org.apache.commons.dbcp2.BasicDataSource;
import org.sleuthkit.autopsy.casemodule.CaseActionCancelledException;
import org.sleuthkit.autopsy.casemodule.CaseActionException;
import org.sleuthkit.autopsy.coordinationservice.CoordinationService;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
@@ -34,7 +32,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
* Central Repository database implementation using Postgres as a
* backend
*/
public class PostgresEamDb extends AbstractSqlEamDb {
final class PostgresEamDb extends AbstractSqlEamDb {
private final static Logger LOGGER = Logger.getLogger(PostgresEamDb.class.getName());
@@ -116,7 +114,7 @@ public class PostgresEamDb extends AbstractSqlEamDb {
String instancesTemplate = "TRUNCATE TABLE %s_instances RESTART IDENTITY CASCADE";
String referencesTemplate = "TRUNCATE TABLE reference_%s RESTART IDENTITY CASCADE";
for (CorrelationAttribute.Type type : DEFAULT_CORRELATION_TYPES) {
for (CorrelationAttribute.Type type : defaultCorrelationTypes) {
dropContent.executeUpdate(String.format(instancesTemplate, type.getDbTableName()));
// FUTURE: support other reference types
if (type.getId() == CorrelationAttribute.FILES_TYPE_ID) {
@@ -35,6 +35,8 @@ import org.sleuthkit.autopsy.coreutils.TextConverterException;
/**
* Settings for the Postgres implementation of the Central Repository database
*
* NOTE: This is public scope because the options panel calls it directly to set/get
*/
public final class PostgresEamDbSettings {
@@ -42,7 +44,6 @@ public final class PostgresEamDbSettings {
private final String DEFAULT_HOST = ""; // NON-NLS
private final int DEFAULT_PORT = 5432;
private final String DEFAULT_DBNAME = "central_repository"; // NON-NLS
private final int DEFAULT_BULK_THRESHHOLD = 1000;
private final String DEFAULT_USERNAME = "";
private final String DEFAULT_PASSWORD = "";
private final String VALIDATION_QUERY = "SELECT version()"; // NON-NLS
@@ -89,15 +90,15 @@ public final class PostgresEamDbSettings {
try {
String bulkThresholdString = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.bulkThreshold"); // NON-NLS
if (bulkThresholdString == null || bulkThresholdString.isEmpty()) {
this.bulkThreshold = DEFAULT_BULK_THRESHHOLD;
this.bulkThreshold = AbstractSqlEamDb.DEFAULT_BULK_THRESHHOLD;
} else {
this.bulkThreshold = Integer.parseInt(bulkThresholdString);
if (getBulkThreshold() <= 0) {
this.bulkThreshold = DEFAULT_BULK_THRESHHOLD;
this.bulkThreshold = AbstractSqlEamDb.DEFAULT_BULK_THRESHHOLD;
}
}
} catch (NumberFormatException ex) {
this.bulkThreshold = DEFAULT_BULK_THRESHHOLD;
this.bulkThreshold = AbstractSqlEamDb.DEFAULT_BULK_THRESHHOLD;
}
userName = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.user"); // NON-NLS
@@ -139,7 +140,7 @@ public final class PostgresEamDbSettings {
*
* @return
*/
public String getConnectionURL(boolean usePostgresDb) {
String getConnectionURL(boolean usePostgresDb) {
StringBuilder url = new StringBuilder();
url.append(getJDBCBaseURI());
url.append(getHost());
@@ -231,7 +232,7 @@ public final class PostgresEamDbSettings {
* Use the current settings and the schema version query to test the
* database schema.
*
* @return true if successfull connection, else false.
* @return true if successful connection, else false.
*/
public boolean verifyDatabaseSchema() {
Connection conn = getEphemeralConnection(false);
@@ -493,7 +494,7 @@ public final class PostgresEamDbSettings {
return result;
}
public boolean isChanged() {
boolean isChanged() {
String hostString = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.host"); // NON-NLS
String portString = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.port"); // NON-NLS
String dbNameString = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.dbName"); // NON-NLS
@@ -568,7 +569,7 @@ public final class PostgresEamDbSettings {
/**
* @return the bulkThreshold
*/
public int getBulkThreshold() {
int getBulkThreshold() {
return bulkThreshold;
}
@@ -622,21 +623,21 @@ public final class PostgresEamDbSettings {
/**
* @return the VALIDATION_QUERY
*/
public String getValidationQuery() {
String getValidationQuery() {
return VALIDATION_QUERY;
}
/**
* @return the POSTGRES_DRIVER
*/
public String getDriver() {
String getDriver() {
return JDBC_DRIVER;
}
/**
* @return the JDBC_BASE_URI
*/
public String getJDBCBaseURI() {
String getJDBCBaseURI() {
return JDBC_BASE_URI;
}
@@ -18,7 +18,6 @@
*/
package org.sleuthkit.autopsy.centralrepository.datamodel;
import java.io.File;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
@@ -38,7 +37,7 @@ import org.sleuthkit.autopsy.coordinationservice.CoordinationService;
* All methods in AbstractSqlEamDb that read or write to the database should
* be overriden here and use appropriate locking.
*/
public class SqliteEamDb extends AbstractSqlEamDb {
final class SqliteEamDb extends AbstractSqlEamDb {
private final static Logger LOGGER = Logger.getLogger(SqliteEamDb.class.getName());
@@ -125,7 +124,7 @@ public class SqliteEamDb extends AbstractSqlEamDb {
String instancesTemplate = "DELETE FROM %s_instances";
String referencesTemplate = "DELETE FROM global_files";
for (CorrelationAttribute.Type type : DEFAULT_CORRELATION_TYPES) {
for (CorrelationAttribute.Type type : defaultCorrelationTypes) {
dropContent.executeUpdate(String.format(instancesTemplate, type.getDbTableName()));
// FUTURE: support other reference types
if (type.getId() == CorrelationAttribute.FILES_TYPE_ID) {
@@ -417,8 +416,8 @@ public class SqliteEamDb extends AbstractSqlEamDb {
} finally {
releaseSharedLock();
}
}
}
/**
* Retrieves eamArtifact instances from the database that are associated
* with the aType and filePath
@@ -590,6 +589,24 @@ public class SqliteEamDb extends AbstractSqlEamDb {
}
}
/**
*
* Gets list of matching eamArtifact instances that have knownStatus =
* "Bad".
* @param aType EamArtifact.Type to search for
* @return List with 0 or more matching eamArtifact instances.
* @throws EamDbException
*/
@Override
public List<CorrelationAttributeInstance> getArtifactInstancesKnownBad(CorrelationAttribute.Type aType) throws EamDbException {
try{
acquireSharedLock();
return super.getArtifactInstancesKnownBad(aType);
} finally {
releaseSharedLock();
}
}
/**
* Count matching eamArtifacts instances that have knownStatus = "Bad".
*
@@ -662,6 +679,22 @@ public class SqliteEamDb extends AbstractSqlEamDb {
}
}
/**
* Process the Artifact instance in the EamDb
*
* @param type EamArtifact.Type to search for
* @param instanceTableCallback callback to process the instance
* @throws EamDbException
*/
@Override
public void processInstanceTable(CorrelationAttribute.Type type, InstanceTableCallback instanceTableCallback) throws EamDbException {
try {
acquireSharedLock();
super.processInstanceTable(type, instanceTableCallback);
} finally {
releaseSharedLock();
}
}
/**
* Check whether a reference set with the given name/version is in the central repo.
* Used to check for name collisions when creating reference sets.
@@ -708,7 +741,7 @@ public class SqliteEamDb extends AbstractSqlEamDb {
* @throws EamDbException
*/
@Override
public long newOrganization(EamOrganization eamOrg) throws EamDbException {
public EamOrganization newOrganization(EamOrganization eamOrg) throws EamDbException {
try{
acquireExclusiveLock();
return super.newOrganization(eamOrg);
@@ -35,13 +35,14 @@ import org.sleuthkit.autopsy.coreutils.PlatformUtil;
/**
* Settings for the sqlite implementation of the Central Repository database
*
* NOTE: This is public scope because the options panel calls it directly to set/get
*/
public final class SqliteEamDbSettings {
private final static Logger LOGGER = Logger.getLogger(SqliteEamDbSettings.class.getName());
private final String DEFAULT_DBNAME = "central_repository.db"; // NON-NLS
private final String DEFAULT_DBDIRECTORY = PlatformUtil.getUserDirectory() + File.separator + "central_repository"; // NON-NLS
private final int DEFAULT_BULK_THRESHHOLD = 1000;
private final String JDBC_DRIVER = "org.sqlite.JDBC"; // NON-NLS
private final String JDBC_BASE_URI = "jdbc:sqlite:"; // NON-NLS
private final String VALIDATION_QUERY = "SELECT count(*) from sqlite_master"; // NON-NLS
@@ -75,15 +76,15 @@ public final class SqliteEamDbSettings {
try {
String bulkThresholdString = ModuleSettings.getConfigSetting("CentralRepository", "db.sqlite.bulkThreshold"); // NON-NLS
if (bulkThresholdString == null || bulkThresholdString.isEmpty()) {
this.bulkThreshold = DEFAULT_BULK_THRESHHOLD;
this.bulkThreshold = AbstractSqlEamDb.DEFAULT_BULK_THRESHHOLD;
} else {
this.bulkThreshold = Integer.parseInt(bulkThresholdString);
if (getBulkThreshold() <= 0) {
this.bulkThreshold = DEFAULT_BULK_THRESHHOLD;
this.bulkThreshold = AbstractSqlEamDb.DEFAULT_BULK_THRESHHOLD;
}
}
} catch (NumberFormatException ex) {
this.bulkThreshold = DEFAULT_BULK_THRESHHOLD;
this.bulkThreshold = AbstractSqlEamDb.DEFAULT_BULK_THRESHHOLD;
}
}
@@ -162,7 +163,7 @@ public final class SqliteEamDbSettings {
*
* @return
*/
public String getConnectionURL() {
String getConnectionURL() {
StringBuilder url = new StringBuilder();
url.append(getJDBCBaseURI());
url.append(getFileNameWithPath());
@@ -439,7 +440,7 @@ public final class SqliteEamDbSettings {
return result;
}
public boolean isChanged() {
boolean isChanged() {
String dbNameString = ModuleSettings.getConfigSetting("CentralRepository", "db.sqlite.dbName"); // NON-NLS
String dbDirectoryString = ModuleSettings.getConfigSetting("CentralRepository", "db.sqlite.dbDirectory"); // NON-NLS
String bulkThresholdString = ModuleSettings.getConfigSetting("CentralRepository", "db.sqlite.bulkThreshold"); // NON-NLS
@@ -474,14 +475,14 @@ public final class SqliteEamDbSettings {
/**
* @return the bulkThreshold
*/
public int getBulkThreshold() {
int getBulkThreshold() {
return bulkThreshold;
}
/**
* @param bulkThreshold the bulkThreshold to set
*/
public void setBulkThreshold(int bulkThreshold) throws EamDbException {
void setBulkThreshold(int bulkThreshold) throws EamDbException {
if (bulkThreshold > 0) {
this.bulkThreshold = bulkThreshold;
} else {
@@ -525,21 +526,21 @@ public final class SqliteEamDbSettings {
/**
* @return the DRIVER
*/
public String getDriver() {
String getDriver() {
return JDBC_DRIVER;
}
/**
* @return the VALIDATION_QUERY
*/
public String getValidationQuery() {
String getValidationQuery() {
return VALIDATION_QUERY;
}
/**
* @return the JDBC_BASE_URI
*/
public String getJDBCBaseURI() {
String getJDBCBaseURI() {
return JDBC_BASE_URI;
}
@@ -102,10 +102,14 @@ final class IngestModule implements FileIngestModule {
return ProcessResult.ERROR;
}
if (!EamArtifactUtil.isValidCentralRepoFile(abstractFile)) {
if (!EamArtifactUtil.isSupportedAbstractFileType(abstractFile)) {
return ProcessResult.OK;
}
if (abstractFile.getKnown() == TskData.FileKnown.KNOWN) {
return ProcessResult.OK;
}
EamDb dbManager;
try {
dbManager = EamDb.getInstance();
@@ -36,9 +36,10 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
/**
* Dialog to add a new organization to the Central Repository database
*/
public class AddNewOrganizationDialog extends javax.swing.JDialog {
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class AddNewOrganizationDialog extends javax.swing.JDialog {
private static final Logger LOGGER = Logger.getLogger(AddNewOrganizationDialog.class.getName());
private static final Logger logger = Logger.getLogger(AddNewOrganizationDialog.class.getName());
private static final long serialVersionUID = 1L;
private final Collection<JTextField> textBoxes;
@@ -51,7 +52,7 @@ public class AddNewOrganizationDialog extends javax.swing.JDialog {
* Creates new form AddNewOrganizationDialog
*/
@Messages({"AddNewOrganizationDialog.addNewOrg.msg=Add New Organization"})
public AddNewOrganizationDialog() {
AddNewOrganizationDialog() {
super((JFrame) WindowManager.getDefault().getMainWindow(),
Bundle.AddNewOrganizationDialog_addNewOrg_msg(),
true); // NON-NLS
@@ -65,6 +66,7 @@ public class AddNewOrganizationDialog extends javax.swing.JDialog {
display();
}
// populates the dialog with existing case information to edit
public AddNewOrganizationDialog(EamOrganization orgToEdit) {
super((JFrame) WindowManager.getDefault().getMainWindow(),
Bundle.AddNewOrganizationDialog_addNewOrg_msg(),
@@ -193,10 +195,19 @@ public class AddNewOrganizationDialog extends javax.swing.JDialog {
}
}
/**
*
* @return True if new org was added or existing org changed
*/
public boolean isChanged() {
return hasChanged;
}
/**
* Only valid if isChanged() is true.
*
* @return Org that was added or changed. null if nothing changed
*/
public EamOrganization getNewOrg() {
return newOrg;
}
@@ -332,12 +343,12 @@ public class AddNewOrganizationDialog extends javax.swing.JDialog {
try {
EamDb dbManager = EamDb.getInstance();
if (organizationToEdit != null) {
//check if new name exists with ID other than the one in use here
newOrg = new EamOrganization(organizationToEdit.getOrgID(),
tfOrganizationName.getText(),
tfPocName.getText(),
tfPocEmail.getText(),
tfPocPhone.getText());
// make a copy in case the update fails
newOrg = dbManager.getOrganizationByID(organizationToEdit.getOrgID());
newOrg.setName(tfOrganizationName.getText());
newOrg.setPocName(tfPocName.getText());
newOrg.setPocEmail(tfPocEmail.getText());
newOrg.setPocPhone(tfPocPhone.getText());
dbManager.updateOrganization(newOrg);
} else {
newOrg = new EamOrganization(
@@ -345,13 +356,14 @@ public class AddNewOrganizationDialog extends javax.swing.JDialog {
tfPocName.getText(),
tfPocEmail.getText(),
tfPocPhone.getText());
newOrg.setOrgID((int)dbManager.newOrganization(newOrg));
newOrg = dbManager.newOrganization(newOrg);
}
hasChanged = true;
dispose();
} catch (EamDbException ex) {
lbWarningMsg.setText(Bundle.AddNewOrganizationDialog_bnOk_addFailed_text());
LOGGER.log(Level.SEVERE, "Failed adding new organization.", ex);
logger.log(Level.SEVERE, "Failed adding new organization.", ex);
newOrg = null;
}
}//GEN-LAST:event_bnOKActionPerformed
@@ -41,6 +41,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.SqliteEamDbSettings;
/**
* Main settings panel for the Central Repository
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel {
private static final long serialVersionUID = 1L;
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2017-18 Basis Technology Corp.
* Copyright 2017-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -48,6 +48,7 @@ import org.sleuthkit.datamodel.TskCoreException;
* CVTTopComponent when this tab is active allowing for context sensitive
* actions to work correctly.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public final class AccountsBrowser extends JPanel implements ExplorerManager.Provider, Lookup.Provider {
private static final long serialVersionUID = 1L;
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2017-18 Basis Technology Corp.
* Copyright 2017-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -42,6 +42,7 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined;
@TopComponent.Registration(mode = "cvt", openAtStartup = false)
@RetainLocation("cvt")
@NbBundle.Messages("CVTTopComponent.name= Communications Visualization")
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public final class CVTTopComponent extends TopComponent {
private static final long serialVersionUID = 1L;
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2017-18 Basis Technology Corp.
* Copyright 2017-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -57,6 +57,7 @@ import org.sleuthkit.datamodel.TskCoreException;
* Panel that holds the Filter control widgets and triggers queries against the
* CommunicationsManager on user filtering changes.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final public class FiltersPanel extends JPanel {
private static final long serialVersionUID = 1L;
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2017-18 Basis Technology Corp.
* Copyright 2017-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -41,6 +41,7 @@ import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
* messages and other account details, and a ContentViewer to show individual
* messages.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public final class MessageBrowser extends JPanel implements ExplorerManager.Provider, Lookup.Provider {
private static final long serialVersionUID = 1L;
@@ -76,6 +76,7 @@ import org.sleuthkit.datamodel.TskData;
@ServiceProviders(value = {
@ServiceProvider(service = FrameCapture.class)
})
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public class FXVideoPanel extends MediaViewVideoPanel {
// Refer to https://docs.oracle.com/javafx/2/api/javafx/scene/media/package-summary.html
@@ -36,6 +36,7 @@ import org.sleuthkit.datamodel.AbstractFile;
* Generic Application content viewer
*/
@ServiceProvider(service = DataContentViewer.class, position = 3)
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public class FileViewer extends javax.swing.JPanel implements DataContentViewer {
private static final int CONFIDENCE_LEVEL = 5;
@@ -30,6 +30,7 @@ import org.sleuthkit.datamodel.AbstractFile;
/**
* Media content viewer for videos, sounds and images.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class MediaFileViewer extends javax.swing.JPanel implements FileTypeViewer {
private static final Logger LOGGER = Logger.getLogger(MediaFileViewer.class.getName());
@@ -48,7 +48,6 @@ import org.openide.util.NbBundle;
import org.python.google.common.collect.Lists;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.ImageUtils;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.FileNode;
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
import org.sleuthkit.datamodel.AbstractFile;
@@ -60,12 +59,11 @@ import org.sleuthkit.datamodel.AbstractFile;
@NbBundle.Messages({"MediaViewImagePanel.externalViewerButton.text=Open in External Viewer",
"MediaViewImagePanel.errorLabel.text=Could not load file into Media View.",
"MediaViewImagePanel.errorLabel.OOMText=Could not load file into Media View: insufficent memory."})
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPanel {
private static final Image EXTERNAL = new Image(MediaViewImagePanel.class.getResource("/org/sleuthkit/autopsy/images/external.png").toExternalForm());
private static final Logger LOGGER = Logger.getLogger(MediaViewImagePanel.class.getName());
private final boolean fxInited;
private JFXPanel fxPanel;
@@ -71,6 +71,7 @@ import org.sleuthkit.datamodel.TskCoreException;
* Shows SMS/MMS/EMail messages
*/
@ServiceProvider(service = DataContentViewer.class, position = 5)
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public class MessageContentViewer extends javax.swing.JPanel implements DataContentViewer {
private static final long serialVersionUID = 1L;
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2014 Basis Technology Corp.
* Copyright 2013-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -36,6 +36,7 @@ import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
* different order and allows the full path to be visible in the bottom area.
*/
@ServiceProvider(service = DataContentViewer.class, position = 6)
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public class Metadata extends javax.swing.JPanel implements DataContentViewer {
/**
@@ -222,7 +223,6 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer {
@Override
public void resetComponent() {
setText("");
return;
}
@Override
@@ -49,6 +49,7 @@ import org.openide.util.actions.Presenter;
/**
* Panel to display a SQLite table
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class SQLiteTableView extends JPanel implements ExplorerManager.Provider {
private final org.openide.explorer.view.OutlineView outlineView;
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -206,7 +206,7 @@ public class Installer extends ModuleInstall {
// Prevent the Autopsy UI from shrinking on high DPI displays
System.setProperty("sun.java2d.dpiaware", "false");
System.setProperty("prism.allowhidpi", "false");
// Update existing configuration in case of unsupported settings
updateConfig();
@@ -218,16 +218,16 @@ public class Installer extends ModuleInstall {
packageInstallers.add(org.sleuthkit.autopsy.centralrepository.eventlisteners.Installer.getDefault());
packageInstallers.add(org.sleuthkit.autopsy.healthmonitor.Installer.getDefault());
}
/**
* If the mode in the configuration file is 'REVIEW' (2, now invalid), this
* method will set it to 'STANDALONE' (0) and disable auto ingest.
*/
private void updateConfig() {
String mode = ModuleSettings.getConfigSetting(SETTINGS_PROPERTIES, "AutopsyMode");
if(mode != null) {
if (mode != null) {
int ordinal = Integer.parseInt(mode);
if(ordinal > 1) {
if (ordinal > 1) {
UserPreferences.setMode(UserPreferences.SelectedMode.STANDALONE);
ModuleSettings.setConfigSetting(UserPreferences.SETTINGS_PROPERTIES, "JoinAutoModeCluster", Boolean.toString(false));
}
@@ -268,6 +268,19 @@ public class Installer extends ModuleInstall {
}
}
/**
* Make a folder in the config directory for object detection classifiers if one does not
* exist.
*/
private static void ensureClassifierFolderExists() {
File objectDetectionClassifierDir = new File(PlatformUtil.getObjectDetectionClassifierPath());
objectDetectionClassifierDir.mkdir();
}
/**
* Make a folder in the config directory for Python Modules if one does not
* exist.
*/
private static void ensurePythonModulesFolderExists() {
File pythonModulesDir = new File(PlatformUtil.getUserPythonModulesPath());
pythonModulesDir.mkdir();
@@ -277,6 +290,7 @@ public class Installer extends ModuleInstall {
public void restored() {
super.restored();
ensurePythonModulesFolderExists();
ensureClassifierFolderExists();
initJavaFx();
for (ModuleInstall mi : packageInstallers) {
try {
@@ -66,7 +66,7 @@ import org.sleuthkit.autopsy.report.ReportBranding;
"AutopsyOptionsPanel.agencyLogoPathFieldValidationLabel.pathNotSet.text=Agency logo path must be set.",
"AutopsyOptionsPanel.logNumAlert.invalidInput.text=A positive integer is required here."
})
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class AutopsyOptionsPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2014 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -38,8 +38,9 @@ import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException;
/**
*
* Data content panel.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public class DataContentPanel extends javax.swing.JPanel implements DataContent, ChangeListener {
private static Logger logger = Logger.getLogger(DataContentPanel.class.getName());
@@ -241,7 +242,7 @@ public class DataContentPanel extends javax.swing.JPanel implements DataContent,
private static class UpdateWrapper {
private DataContentViewer wrapped;
private final DataContentViewer wrapped;
private boolean outdated;
UpdateWrapper(DataContentViewer wrapped) {
@@ -43,6 +43,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
//@TopComponent.Description(preferredID = "DataContentTopComponent")
//@TopComponent.Registration(mode = "output", openAtStartup = true)
//@TopComponent.OpenActionRegistration(displayName = "#CTL_DataContentAction", preferredID = "DataContentTopComponent")
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public final class DataContentTopComponent extends TopComponent implements DataContent, ExplorerManager.Provider {
private static final Logger logger = Logger.getLogger(DataContentTopComponent.class.getName());
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2013 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -63,6 +63,7 @@ import org.netbeans.swing.etable.ETable;
* in a JTable representation of its BlackboardAttributes.
*/
@ServiceProvider(service = DataContentViewer.class, position = 7)
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public class DataContentViewerArtifact extends javax.swing.JPanel implements DataContentViewer {
@NbBundle.Messages({
@@ -484,7 +485,8 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
if ((artifact == null)
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID())
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID())
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID())) {
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID())
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID())) {
return 3;
} else {
return 6;
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2016 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,7 +27,6 @@ import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JTextPane;
import javax.swing.text.BadLocationException;
import javax.swing.text.Utilities;
import org.openide.nodes.Node;
@@ -40,6 +39,7 @@ import org.sleuthkit.datamodel.TskException;
/**
* Hex view of file contents.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
@ServiceProvider(service = DataContentViewer.class, position = 1)
public class DataContentViewerHex extends javax.swing.JPanel implements DataContentViewer {
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -28,9 +28,7 @@ import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JTextPane;
import org.openide.nodes.Node;
import org.openide.util.Lookup;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
import org.sleuthkit.autopsy.coreutils.StringExtract;
@@ -44,11 +42,12 @@ import org.sleuthkit.datamodel.TskException;
* Viewer displays strings extracted from contents.
*/
@ServiceProvider(service = DataContentViewer.class, position = 2)
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public class DataContentViewerString extends javax.swing.JPanel implements DataContentViewer {
private static long currentOffset = 0;
private static final long pageLength = 16384;
private final byte[] data = new byte[(int) pageLength];
private static final long PAGE_LENGTH = 16384;
private final byte[] data = new byte[(int) PAGE_LENGTH];
private static int currentPage = 1;
private Content dataSource;
//string extract utility
@@ -62,7 +61,7 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC
initComponents();
customizeComponents();
this.resetComponent();
logger.log(Level.INFO, "Created StringView instance: " + this); //NON-NLS
logger.log(Level.INFO, "Created StringView instance: {0}", this); //NON-NLS
}
private void customizeComponents() {
@@ -264,7 +263,7 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC
private void prevPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prevPageButtonActionPerformed
//@@@ this is part of the code dealing with the data viewer. could be copied/removed to implement the scrollbar
currentOffset -= pageLength;
currentOffset -= PAGE_LENGTH;
currentPage = currentPage - 1;
currentPageLabel.setText(Integer.toString(currentPage));
setDataView(dataSource, currentOffset);
@@ -272,7 +271,7 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC
private void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextPageButtonActionPerformed
//@@@ this is part of the code dealing with the data viewer. could be copied/removed to implement the scrollbar
currentOffset += pageLength;
currentOffset += PAGE_LENGTH;
currentPage = currentPage + 1;
currentPageLabel.setText(Integer.toString(currentPage));
setDataView(dataSource, currentOffset);
@@ -281,7 +280,7 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC
private void goToPageTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_goToPageTextFieldActionPerformed
String pageNumberStr = goToPageTextField.getText();
int pageNumber;
int maxPage = Math.round((dataSource.getSize() - 1) / pageLength) + 1;
int maxPage = Math.round((dataSource.getSize() - 1) / PAGE_LENGTH) + 1;
try {
pageNumber = Integer.parseInt(pageNumberStr);
} catch (NumberFormatException ex) {
@@ -297,7 +296,7 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC
JOptionPane.WARNING_MESSAGE);
return;
}
currentOffset = (pageNumber - 1) * pageLength;
currentOffset = (pageNumber - 1) * PAGE_LENGTH;
currentPage = pageNumber;
currentPageLabel.setText(Integer.toString(currentPage));
setDataView(dataSource, currentOffset);
@@ -352,11 +351,11 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC
String text = "";
if (dataSource.getSize() > 0) {
try {
bytesRead = dataSource.read(data, offset, pageLength); // read the data
bytesRead = dataSource.read(data, offset, PAGE_LENGTH); // read the data
} catch (TskException ex) {
text = NbBundle.getMessage(this.getClass(),
"DataContentViewerString.setDataView.errorText", currentOffset,
currentOffset + pageLength);
currentOffset + PAGE_LENGTH);
logger.log(Level.WARNING, "Error while trying to show the String content.", ex); //NON-NLS
}
}
@@ -370,15 +369,15 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC
if (text.trim().isEmpty()) {
text = NbBundle.getMessage(this.getClass(),
"DataContentViewerString.setDataView.errorNoText", currentOffset,
currentOffset + pageLength);
currentOffset + PAGE_LENGTH);
}
} else {
text = NbBundle.getMessage(this.getClass(), "DataContentViewerString.setDataView.errorText", currentOffset,
currentOffset + pageLength);
currentOffset + PAGE_LENGTH);
}
// disable or enable the next button
if (offset + pageLength < dataSource.getSize()) {
if (offset + PAGE_LENGTH < dataSource.getSize()) {
nextPageButton.setEnabled(true);
} else {
nextPageButton.setEnabled(false);
@@ -391,7 +390,7 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC
prevPageButton.setEnabled(true);
}
int totalPage = Math.round((dataSource.getSize() - 1) / pageLength) + 1;
int totalPage = Math.round((dataSource.getSize() - 1) / PAGE_LENGTH) + 1;
totalPageLabel.setText(Integer.toString(totalPage));
currentPageLabel.setText(Integer.toString(currentPage));
outputViewPane.setText(text); // set the output view
@@ -500,11 +499,7 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC
return false;
}
Content content = node.getLookup().lookup(Content.class);
if (content != null && content.getSize() > 0) {
return true;
}
return false;
return (content != null && content.getSize() > 0);
}
@Override
@@ -72,6 +72,7 @@ import org.sleuthkit.autopsy.datamodel.NodeSelectionInfo;
* (DataContentTopComponent) that is normally docked into the lower right hand
* side of the main application window, or it could be a custom content view.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public class DataResultPanel extends javax.swing.JPanel implements DataResult, ChangeListener, ExplorerManager.Provider {
private static final long serialVersionUID = 1L;
@@ -451,7 +452,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
}
}
}
};
}
if (tabToSelect == NO_TAB_SELECTED) {
tabToSelect = resultViewerTabs.getSelectedIndex();
if ((tabToSelect == NO_TAB_SELECTED) || (!resultViewerTabs.isEnabledAt(tabToSelect))) {
@@ -68,6 +68,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
* viewers to the actions global context.
*/
@RetainLocation("editor")
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public final class DataResultTopComponent extends TopComponent implements DataResult, ExplorerManager.Provider {
private static final Logger logger = Logger.getLogger(DataResultTopComponent.class.getName());
@@ -77,6 +77,7 @@ import org.sleuthkit.autopsy.datamodel.NodeSelectionInfo;
* ancestor top component's explorer manager at runtime.
*/
@ServiceProvider(service = DataResultViewer.class)
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public final class DataResultViewerTable extends AbstractDataResultViewer {
private static final long serialVersionUID = 1L;
@@ -71,6 +71,7 @@ import org.sleuthkit.datamodel.TskCoreException;
* ancestor top component's explorer manager at runtime.
*/
@ServiceProvider(service = DataResultViewer.class)
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public final class DataResultViewerThumbnail extends AbstractDataResultViewer {
private static final long serialVersionUID = 1L;
@@ -372,10 +373,7 @@ public final class DataResultViewerThumbnail extends AbstractDataResultViewer {
@Override
public boolean isSupported(Node selectedNode) {
if (selectedNode == null) {
return false;
}
return true;
return (selectedNode != null);
}
@Override
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2015 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -52,8 +52,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
@Messages("CTL_OfflineHelpAction=Offline Autopsy Documentation")
public final class OfflineHelpAction implements ActionListener {
private URI uri;
private static final Logger Logger
private static final Logger logger
= org.sleuthkit.autopsy.coreutils.Logger.getLogger(AboutWindowPanel.class.getName());
@Override
@@ -71,7 +70,8 @@ public final class OfflineHelpAction implements ActionListener {
String fileForHelp = "";
String indexForHelp = "";
String currentDirectory = "";
URI uri = null;
try {
// Match the form: file:///C:/some/directory/AutopsyXYZ/docs/index.html
fileForHelp = NbBundle.getMessage(OfflineHelpAction.class, "FILE_FOR_LOCAL_HELP");
@@ -79,7 +79,7 @@ public final class OfflineHelpAction implements ActionListener {
currentDirectory = System.getProperty("user.dir").replace("\\", "/").replace(" ", "%20"); //NON-NLS
uri = new URI(fileForHelp + currentDirectory + indexForHelp);
} catch (Exception ex) {
Logger.log(Level.SEVERE, "Unable to load Offline Documentation: "
logger.log(Level.SEVERE, "Unable to load Offline Documentation: "
+ fileForHelp + currentDirectory + indexForHelp, ex); //NON-NLS
}
if (uri != null) {
@@ -89,7 +89,7 @@ public final class OfflineHelpAction implements ActionListener {
try {
desktop.browse(uri);
} catch (IOException ex) {
Logger.log(Level.SEVERE, "Unable to launch the system browser: "
logger.log(Level.SEVERE, "Unable to launch the system browser: "
+ fileForHelp + currentDirectory + indexForHelp, ex); //NON-NLS
}
} else {
@@ -98,7 +98,7 @@ public final class OfflineHelpAction implements ActionListener {
try {
HtmlBrowser.URLDisplayer.getDefault().showURL(uri.toURL());
} catch (MalformedURLException ex) {
Logger.log(Level.SEVERE, "Unable to launch the built-in browser: "
logger.log(Level.SEVERE, "Unable to launch the built-in browser: "
+ fileForHelp + currentDirectory + indexForHelp, ex); //NON-NLS
}
}
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-17 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -29,6 +29,7 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined;
* A dialog that allows the user to choose sort criteria for the thumbnail
* viewer.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class SortChooser extends javax.swing.JPanel {
/**
@@ -59,10 +59,11 @@ import javax.imageio.stream.ImageInputStream;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.opencv.core.Core;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.corelibs.OpenCvLoader;
import org.sleuthkit.autopsy.corelibs.ScalrWrapper;
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector.FileTypeDetectorInitException;
@@ -96,7 +97,7 @@ public class ImageUtils {
private static final List<String> SUPPORTED_IMAGE_EXTENSIONS = new ArrayList<>();
private static final SortedSet<String> SUPPORTED_IMAGE_MIME_TYPES;
private static final boolean OPEN_CV_LOADED;
private static final boolean FFMPEG_LOADED;
/**
* Map from tsk object id to Java File object. Used to get the same File for
@@ -105,6 +106,8 @@ public class ImageUtils {
*
* NOTE: Must be cleared when the case is changed.
*/
@Messages({"ImageUtils.ffmpegLoadedError.title=OpenCV FFMpeg",
"ImageUtils.ffmpegLoadedError.msg=OpenCV FFMpeg library failed to load, see log for more details"})
private static final ConcurrentHashMap<Long, File> cacheFileMap = new ConcurrentHashMap<>();
static {
@@ -117,25 +120,23 @@ public class ImageUtils {
tempImage = null;
}
DEFAULT_THUMBNAIL = tempImage;
//load opencv libraries
boolean openCVLoadedTemp;
try {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
if (System.getProperty("os.arch").equals("amd64") || System.getProperty("os.arch").equals("x86_64")) { //NON-NLS
System.loadLibrary("opencv_ffmpeg248_64"); //NON-NLS
} else {
System.loadLibrary("opencv_ffmpeg248"); //NON-NLS
boolean tempFfmpegLoaded = false;
if (OpenCvLoader.isOpenCvLoaded()) {
try {
if (System.getProperty("os.arch").equals("amd64") || System.getProperty("os.arch").equals("x86_64")) { //NON-NLS
System.loadLibrary("opencv_ffmpeg2413_64"); //NON-NLS
} else {
System.loadLibrary("opencv_ffmpeg2413"); //NON-NLS
}
tempFfmpegLoaded = true;
} catch (UnsatisfiedLinkError e) {
tempFfmpegLoaded = false;
LOGGER.log(Level.SEVERE, Bundle.ImageUtils_ffmpegLoadedError_msg(), e); //NON-NLS
MessageNotifyUtil.Notify.show(Bundle.ImageUtils_ffmpegLoadedError_title(), Bundle.ImageUtils_ffmpegLoadedError_msg(), MessageNotifyUtil.MessageType.WARNING);
}
openCVLoadedTemp = true;
} catch (UnsatisfiedLinkError e) {
openCVLoadedTemp = false;
LOGGER.log(Level.SEVERE, "OpenCV Native code library failed to load", e); //NON-NLS
MessageNotifyUtil.Notify.show("Open CV", "OpenCV native library failed to load, see log for more details", MessageNotifyUtil.MessageType.WARNING);
}
FFMPEG_LOADED = tempFfmpegLoaded;
OPEN_CV_LOADED = openCVLoadedTemp;
SUPPORTED_IMAGE_EXTENSIONS.addAll(Arrays.asList(ImageIO.getReaderFileSuffixes()));
SUPPORTED_IMAGE_EXTENSIONS.add("tec"); // Add JFIF .tec files
SUPPORTED_IMAGE_EXTENSIONS.removeIf("db"::equals); // remove db files
@@ -165,8 +166,8 @@ public class ImageUtils {
/**
* Thread/Executor that saves generated thumbnails to disk in the background
*/
private static final Executor imageSaver =
Executors.newSingleThreadExecutor(new BasicThreadFactory.Builder()
private static final Executor imageSaver
= Executors.newSingleThreadExecutor(new BasicThreadFactory.Builder()
.namingPattern("thumbnail-saver-%d").build()); //NON-NLS
public static List<String> getSupportedImageExtensions() {
@@ -687,7 +688,7 @@ public class ImageUtils {
//There was no correctly-sized cached thumbnail so make one.
BufferedImage thumbnail = null;
if (VideoUtils.isVideoThumbnailSupported(file)) {
if (OPEN_CV_LOADED) {
if (FFMPEG_LOADED) {
updateMessage(Bundle.GetOrGenerateThumbnailTask_generatingPreviewFor(file.getName()));
if (isCancelled()) {
return null;
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2012-2014 Basis Technology Corp.
* Copyright 2012-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -51,6 +51,7 @@ import org.sleuthkit.datamodel.TskCoreException;
public class PlatformUtil {
private static final String PYTHON_MODULES_SUBDIRECTORY = "python_modules"; //NON-NLS
private static final String CLASSIFIERS_SUBDIRECTORY = "object_detection_classifiers"; //NON-NLS
private static String javaPath = null;
public static final String OS_NAME_UNKNOWN = NbBundle.getMessage(PlatformUtil.class, "PlatformUtil.nameUnknown");
public static final String OS_VERSION_UNKNOWN = NbBundle.getMessage(PlatformUtil.class, "PlatformUtil.verUnknown");
@@ -116,6 +117,15 @@ public class PlatformUtil {
return getUserDirectory().getAbsolutePath() + File.separator + PYTHON_MODULES_SUBDIRECTORY;
}
/**
* Get root path where the user's object detection classifiers are stored.
*
* @return Absolute path to the object detection classifiers root directory.
*/
public static String getObjectDetectionClassifierPath() {
return getUserDirectory().getAbsolutePath() + File.separator + CLASSIFIERS_SUBDIRECTORY;
}
/**
* get file path to the java executable binary use embedded java if
* available, otherwise use system java in PATH no validation is done if
@@ -310,19 +320,17 @@ public class PlatformUtil {
return (System.getProperty("os.arch").contains("64")); //NON-NLS
}
}
/**
* Attempts to determine whether the JVM is 64-bit or 32-bit.
* May not be completely reliable for non-Windows operating systems.
* Attempts to determine whether the JVM is 64-bit or 32-bit. May not be
* completely reliable for non-Windows operating systems.
*
* @return True if the JVM is 64-bit. False otherwise.
*/
public static boolean is64BitJVM() {
return (System.getProperty("sun.arch.data.model").equals("64"));
}
/**
* Get a list of all physical drives attached to the client's machine. Error
* threshold of 4 non-existent physical drives before giving up.
@@ -21,12 +21,14 @@ package org.sleuthkit.autopsy.datamodel;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.stream.Collectors;
import javax.swing.Action;
import org.apache.commons.lang3.StringUtils;
import org.openide.nodes.Children;
import org.openide.nodes.Sheet;
@@ -36,6 +38,9 @@ import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent;
import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent;
import org.sleuthkit.autopsy.centralrepository.AddEditCentralRepoCommentAction;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
import org.sleuthkit.autopsy.coreutils.Logger;
import static org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.AbstractFilePropertyType.*;
import static org.sleuthkit.autopsy.datamodel.Bundle.*;
@@ -253,6 +258,21 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
map.put(EXTENSION.toString(), content.getNameExtension());
}
@Override
public Action[] getActions(boolean context) {
List<Action> actionsList = new ArrayList<>();
actionsList.addAll(Arrays.asList(super.getActions(true)));
// Create the "Add/Edit Central Repository Comment" menu item if the enabled.
AbstractFile file = content;
if (EamDbUtil.useCentralRepo() && EamArtifactUtil.isSupportedAbstractFileType(file) && file.isFile()) {
actionsList.add(AddEditCentralRepoCommentAction.createAddEditCentralRepoCommentAction(file));
}
return actionsList.toArray(new Action[actionsList.size()]);
}
/**
* Used by subclasses of AbstractAbstractFileNode to add the tags property
* to their sheets.
@@ -48,6 +48,8 @@ import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagAddedEvent;
import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagDeletedEvent;
import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent;
import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent;
import org.sleuthkit.autopsy.centralrepository.AddEditCentralRepoCommentAction;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import static org.sleuthkit.autopsy.datamodel.DisplayableItemNode.findLinked;
@@ -68,7 +70,7 @@ import org.sleuthkit.datamodel.TskCoreException;
*/
public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifact> {
private static final Logger LOGGER = Logger.getLogger(BlackboardArtifactNode.class.getName());
private static final Logger logger = Logger.getLogger(BlackboardArtifactNode.class.getName());
private static final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED,
Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED,
Case.Events.CONTENT_TAG_ADDED,
@@ -217,6 +219,12 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
public Action[] getActions(boolean context) {
List<Action> actionsList = new ArrayList<>();
actionsList.addAll(Arrays.asList(super.getActions(context)));
AbstractFile file = getLookup().lookup(AbstractFile.class);
// Create the "Add/Edit Central Repository Comment" menu item if the enabled.
if (file != null && file.isFile() && EamDbUtil.useCentralRepo()) {
actionsList.add(AddEditCentralRepoCommentAction.createAddEditCentralRepoCommentAction(file));
}
//if this artifact has a time stamp add the action to view it in the timeline
try {
@@ -224,7 +232,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
actionsList.add(new ViewArtifactInTimelineAction(artifact));
}
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, MessageFormat.format("Error getting arttribute(s) from blackboard artifact{0}.", artifact.getArtifactID()), ex); //NON-NLS
logger.log(Level.SEVERE, MessageFormat.format("Error getting arttribute(s) from blackboard artifact{0}.", artifact.getArtifactID()), ex); //NON-NLS
MessageNotifyUtil.Notify.error(Bundle.BlackboardArtifactNode_getAction_errorTitle(), Bundle.BlackboardArtifactNode_getAction_resultErrorMessage());
}
@@ -235,12 +243,11 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
actionsList.add(ViewFileInTimelineAction.createViewFileAction(c));
}
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, MessageFormat.format("Error getting linked file from blackboard artifact{0}.", artifact.getArtifactID()), ex); //NON-NLS
logger.log(Level.SEVERE, MessageFormat.format("Error getting linked file from blackboard artifact{0}.", artifact.getArtifactID()), ex); //NON-NLS
MessageNotifyUtil.Notify.error(Bundle.BlackboardArtifactNode_getAction_errorTitle(), Bundle.BlackboardArtifactNode_getAction_linkedFileMessage());
}
//if this artifact has associated content, add the action to view the content in the timeline
AbstractFile file = getLookup().lookup(AbstractFile.class);
//if the artifact has associated content, add the action to view the content in the timeline
if (null != file) {
actionsList.add(ViewFileInTimelineAction.createViewSourceFileAction(file));
}
@@ -391,7 +398,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
try {
sourcePath = associated.getUniquePath();
} catch (TskCoreException ex) {
LOGGER.log(Level.WARNING, "Failed to get unique path from: {0}", associated.getName()); //NON-NLS
logger.log(Level.WARNING, "Failed to get unique path from: {0}", associated.getName()); //NON-NLS
}
if (sourcePath.isEmpty() == false) {
@@ -439,7 +446,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
dataSourceStr = getRootParentName();
}
} catch (TskCoreException ex) {
LOGGER.log(Level.WARNING, "Failed to get image name from {0}", associated.getName()); //NON-NLS
logger.log(Level.WARNING, "Failed to get image name from {0}", associated.getName()); //NON-NLS
}
if (dataSourceStr.isEmpty() == false) {
@@ -472,7 +479,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
tags.addAll(Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact));
tags.addAll(Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByContent(associated));
} catch (TskCoreException | NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Failed to get tags for artifact " + artifact.getDisplayName(), ex);
logger.log(Level.SEVERE, "Failed to get tags for artifact " + artifact.getDisplayName(), ex);
}
sheetSet.put(new NodeProperty<>("Tags", Bundle.BlackboardArtifactNode_createSheet_tags_displayName(),
NO_DESCR, tags.stream().map(t -> t.getName().getDisplayName()).collect(Collectors.joining(", "))));
@@ -490,7 +497,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
parentName = parent.getName();
}
} catch (TskCoreException ex) {
LOGGER.log(Level.WARNING, "Failed to get parent name from {0}", associated.getName()); //NON-NLS
logger.log(Level.WARNING, "Failed to get parent name from {0}", associated.getName()); //NON-NLS
return "";
}
return parentName;
@@ -551,7 +558,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
}
}
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Getting attributes failed", ex); //NON-NLS
logger.log(Level.SEVERE, "Getting attributes failed", ex); //NON-NLS
}
}
@@ -614,7 +621,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
return Lookups.fixed(artifact, content);
}
} catch (ExecutionException ex) {
LOGGER.log(Level.WARNING, "Getting associated content for artifact failed", ex); //NON-NLS
logger.log(Level.WARNING, "Getting associated content for artifact failed", ex); //NON-NLS
return Lookups.fixed(artifact);
}
}
@@ -96,8 +96,8 @@ public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
@Override
public Action[] getActions(boolean context) {
List<Action> actionsList = new ArrayList<>();
actionsList.addAll(Arrays.asList(super.getActions(true)));
actionsList.add(new ViewContextAction(NbBundle.getMessage(this.getClass(), "LocalFileNode.viewFileInDir.text"), this.content));
actionsList.add(null); // creates a menu separator
actionsList.add(new NewWindowViewAction(
@@ -33,6 +33,10 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.autopsy.coreutils.PathValidator;
/**
* Allows examiner to supply a raw data source.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class RawDSInputPanel extends JPanel implements DocumentListener {
private static final long TWO_GB = 2000000000L;
private static final long serialVersionUID = 1L; //default
@@ -42,6 +42,10 @@ import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Display statistics on system performance.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public class PerformancePanel extends javax.swing.JDialog {
/**
@@ -31,6 +31,7 @@ import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
/**
* Panel found in an AddRuleDialog
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class AddExternalViewerRulePanel extends javax.swing.JPanel {
private static final Logger logger = Logger.getLogger(AddExternalViewerRulePanel.class.getName());
@@ -97,6 +97,7 @@ import org.sleuthkit.datamodel.TskCoreException;
@Messages({
"DirectoryTreeTopComponent.resultsView.title=Listing"
})
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public final class DirectoryTreeTopComponent extends TopComponent implements DataExplorer, ExplorerManager.Provider {
private final transient ExplorerManager em = new ExplorerManager();
@@ -1059,10 +1060,15 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
DisplayableItemNode undecoratedParentNode = (DisplayableItemNode) ((DirectoryTreeFilterNode) treeNode).getOriginal();
undecoratedParentNode.setChildNodeSelectionInfo(new ArtifactNodeSelectionInfo(art));
getTree().expandNode(treeNode);
try {
em.setExploredContextAndSelection(treeNode, new Node[]{treeNode});
} catch (PropertyVetoException ex) {
LOGGER.log(Level.WARNING, "Property Veto: ", ex); //NON-NLS
if (this.getSelectedNode().equals(treeNode)) {
this.setDirectoryListingActive();
this.respondSelection(em.getSelectedNodes(), new Node[]{treeNode});
} else {
try {
em.setExploredContextAndSelection(treeNode, new Node[]{treeNode});
} catch (PropertyVetoException ex) {
LOGGER.log(Level.WARNING, "Property Veto: ", ex); //NON-NLS
}
}
// Another thread is needed because we have to wait for dataResult to populate
}
@@ -34,6 +34,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
* opening files in external viewers. Users can associate a file by either MIME
* type or by extension to an executable file.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel implements OptionsPanel {
private static final Logger logger = Logger.getLogger(ExternalViewerGlobalSettingsPanel.class.getName());
@@ -27,9 +27,8 @@ import org.sleuthkit.datamodel.TskCoreException;
/**
* This is the form / panel to show the File System Details.
*
* @author jantonius
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class FileSystemDetailsPanel extends javax.swing.JPanel {
private static final Logger logger = Logger.getLogger(FileSystemDetailsPanel.class.getName());
private static final long serialVersionUID = 1L;
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,21 +16,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* ImageDetailsPanel.java
*
* Created on May 2, 2011, 3:53:49 PM
*/
package org.sleuthkit.autopsy.directorytree;
import java.awt.*;
import java.awt.event.ActionListener;
/**
*
* @author jantonius
* Image details panel.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class ImageDetailsPanel extends javax.swing.JPanel {
/**
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,12 +18,12 @@
*/
package org.sleuthkit.autopsy.directorytree;
import java.awt.*;
import java.awt.event.ActionListener;
/**
* This is the form / panel to show the Volume Details.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class VolumeDetailsPanel extends javax.swing.JPanel {
/**
@@ -31,7 +31,6 @@ package org.sleuthkit.autopsy.examples;
import java.awt.Component;
import org.openide.nodes.Node;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException;
@@ -45,6 +44,7 @@ import org.sleuthkit.datamodel.TskCoreException;
* compiled each time to ensure that it is compliant with the API.
*/
// @ServiceProvider(service = DataContentViewer.class)
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class SampleContentViewer extends javax.swing.JPanel implements DataContentViewer {
/**
@@ -36,6 +36,7 @@ import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel;
/**
* UI component used to make per ingest job settings for sample ingest modules.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public class SampleIngestModuleIngestJobSettingsPanel extends IngestModuleIngestJobSettingsPanel {
/**
@@ -6,7 +6,7 @@
<Dimension value="[150, 150]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[100, 100]"/>
<Dimension value="[150, 150]"/>
</Property>
</Properties>
<AuxValues>
@@ -46,8 +46,8 @@
<Group type="102" alignment="1" attributes="0">
<Component id="dataSourceCheckBox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jScrollPane1" pref="95" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jScrollPane1" min="-2" pref="103" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="dataSourceNoteLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
@@ -154,7 +154,7 @@ public class DataSourcePanel extends javax.swing.JPanel {
dataSourceNoteLabel = new javax.swing.JLabel();
setMinimumSize(new java.awt.Dimension(150, 150));
setPreferredSize(new java.awt.Dimension(100, 100));
setPreferredSize(new java.awt.Dimension(150, 150));
dataSourceList.setModel(new javax.swing.AbstractListModel<String>() {
List<String> strings = getDataSourceArray();
@@ -197,8 +197,8 @@ public class DataSourcePanel extends javax.swing.JPanel {
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(dataSourceCheckBox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 95, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 103, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(dataSourceNoteLabel)
.addContainerGap())
);
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -39,6 +39,7 @@ import java.util.Date;
/**
* Subpanel with controls for file data filtering.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class DateSearchPanel extends javax.swing.JPanel {
private final DatePickerSettings fromDateSettings = new DatePickerSettings();
@@ -70,12 +70,12 @@
</Component>
<Component class="javax.swing.JLabel" name="errorLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="FileSearchPanel.errorLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="33" green="33" red="ff" type="rgb"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="FileSearchPanel.errorLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,17 +16,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* FileSearchPanel.java
*
* Created on Mar 5, 2012, 1:51:50 PM
*/
package org.sleuthkit.autopsy.filesearch;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
@@ -37,6 +31,7 @@ import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
@@ -56,9 +51,10 @@ import org.sleuthkit.datamodel.TskCoreException;
/**
* FileSearchPanel that present search options
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class FileSearchPanel extends javax.swing.JPanel {
private final List<FilterArea> filterAreas = new ArrayList<>();
private final List<FileSearchFilter> filters = new ArrayList<>();
private static int resultWindowCount = 0; //keep track of result windows so they get unique names
private static final String EMPTY_WHERE_CLAUSE = NbBundle.getMessage(DateSearchFilter.class, "FileSearchPanel.emptyWhereClause.text");
@@ -79,32 +75,57 @@ class FileSearchPanel extends javax.swing.JPanel {
* This method is called from within the constructor to initialize the form.
*/
private void customizeComponents() {
JLabel label = new JLabel(NbBundle.getMessage(this.getClass(), "FileSearchPanel.custComp.label.text"));
label.setAlignmentX(Component.LEFT_ALIGNMENT);
label.setBorder(new EmptyBorder(0, 0, 10, 0));
filterPanel.add(label);
JPanel panel1 = new JPanel();
panel1.setLayout(new GridLayout(1,2));
panel1.add(new JLabel(""));
JPanel panel2 = new JPanel();
panel2.setLayout(new GridLayout(1,2, 20, 0));
JPanel panel3 = new JPanel();
panel3.setLayout(new GridLayout(1,2, 20, 0));
JPanel panel4 = new JPanel();
panel4.setLayout(new GridLayout(1,2, 20, 0));
JPanel panel5 = new JPanel();
panel5.setLayout(new GridLayout(1,2, 20, 0));
// Create and add filter areas
this.filterAreas.add(new FilterArea(NbBundle.getMessage(this.getClass(), "FileSearchPanel.filterTitle.name"), new NameSearchFilter()));
List<FileSearchFilter> metadataFilters = new ArrayList<>();
metadataFilters.add(new SizeSearchFilter());
metadataFilters.add(new MimeTypeFilter());
metadataFilters.add(new DateSearchFilter());
NameSearchFilter nameFilter = new NameSearchFilter();
SizeSearchFilter sizeFilter = new SizeSearchFilter();
DateSearchFilter dateFilter = new DateSearchFilter();
KnownStatusSearchFilter knowStatusFilter = new KnownStatusSearchFilter();
HashSearchFilter hashFilter = new HashSearchFilter();
MimeTypeFilter mimeTypeFilter = new MimeTypeFilter();
DataSourceFilter dataSourceFilter = new DataSourceFilter();
this.filterAreas.add(new FilterArea(NbBundle.getMessage(this.getClass(), "FileSearchPanel.filterTitle.metadata"), metadataFilters));
this.filterAreas.add(new FilterArea(NbBundle.getMessage(this.getClass(), "FileSearchPanel.filterTitle.knownStatus"), new KnownStatusSearchFilter()));
panel2.add(new FilterArea(NbBundle.getMessage(this.getClass(), "FileSearchPanel.filterTitle.name"),nameFilter));
panel3.add(new FilterArea(NbBundle.getMessage(this.getClass(), "FileSearchPanel.filterTitle.metadata"),sizeFilter));
panel2.add(new FilterArea(NbBundle.getMessage(this.getClass(), "FileSearchPanel.filterTitle.metadata"), dateFilter));
panel3.add(new FilterArea(NbBundle.getMessage(this.getClass(), "FileSearchPanel.filterTitle.knownStatus"), knowStatusFilter));
panel5.add(new FilterArea(NbBundle.getMessage(this.getClass(), "HashSearchPanel.md5CheckBox.text"), hashFilter));
panel5.add(new JLabel(""));
panel4.add(new FilterArea(NbBundle.getMessage(this.getClass(), "FileSearchPanel.filterTitle.metadata"), mimeTypeFilter));
panel4.add(new FilterArea(NbBundle.getMessage(this.getClass(), "DataSourcePanel.dataSourceCheckBox.text"), dataSourceFilter));
filterPanel.add(panel1);
filterPanel.add(panel2);
filterPanel.add(panel3);
filterPanel.add(panel4);
filterPanel.add(panel5);
filters.add(nameFilter);
filters.add(sizeFilter);
filters.add(dateFilter);
filters.add(knowStatusFilter);
filters.add(hashFilter);
filters.add(mimeTypeFilter);
filters.add(dataSourceFilter);
this.filterAreas.add(new FilterArea(NbBundle.getMessage(this.getClass(), "HashSearchPanel.md5CheckBox.text"), new HashSearchFilter()));
this.filterAreas.add(new FilterArea(NbBundle.getMessage(this.getClass(), "DataSourcePanel.dataSourceCheckBox.text"), new DataSourceFilter()));
for (FilterArea fa : this.filterAreas) {
fa.setMaximumSize(new Dimension(Integer.MAX_VALUE, fa.getMinimumSize().height));
fa.setAlignmentX(Component.LEFT_ALIGNMENT);
filterPanel.add(fa);
}
for (FileSearchFilter filter : this.getFilters()) {
filter.addPropertyChangeListener(new PropertyChangeListener() {
@Override
@@ -242,12 +263,6 @@ class FileSearchPanel extends javax.swing.JPanel {
}
private Collection<FileSearchFilter> getFilters() {
Collection<FileSearchFilter> filters = new ArrayList<>();
for (FilterArea fa : this.filterAreas) {
filters.addAll(fa.getFilters());
}
return filters;
}
@@ -265,10 +280,8 @@ class FileSearchPanel extends javax.swing.JPanel {
void addListenerToAll(ActionListener l) {
searchButton.addActionListener(l);
for (FilterArea fa : this.filterAreas) {
for (FileSearchFilter fsf : fa.getFilters()) {
fsf.addActionListener(l);
}
for (FileSearchFilter fsf : getFilters()) {
fsf.addActionListener(l);
}
}
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,8 +27,9 @@ import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
/**
*
* Panel to allow examiner to search for a hash value.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class HashSearchPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,20 +16,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* KnownStatusSearchPanel.java
*
* Created on Oct 19, 2011, 11:45:44 AM
*/
package org.sleuthkit.autopsy.filesearch;
import javax.swing.JCheckBox;
/**
*
* @author pmartel
* Search for known, unknown, and bad files.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class KnownStatusSearchPanel extends javax.swing.JPanel {
/**
@@ -6,7 +6,7 @@
<Dimension value="[150, 150]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[100, 100]"/>
<Dimension value="[150, 150]"/>
</Property>
</Properties>
<AuxValues>
@@ -46,10 +46,10 @@
<Group type="102" alignment="1" attributes="0">
<Component id="mimeTypeCheckBox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jScrollPane1" pref="94" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jScrollPane1" min="-2" pref="103" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<EmptySpace min="40" pref="40" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@@ -89,12 +89,12 @@
</Component>
<Component class="javax.swing.JLabel" name="jLabel1">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="MimeTypePanel.jLabel1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="10" style="0"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="MimeTypePanel.jLabel1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,6 +25,10 @@ import javax.swing.event.ListSelectionEvent;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
/**
* Enter MIME types for search.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public class MimeTypePanel extends javax.swing.JPanel {
private static final Logger logger = Logger.getLogger(MimeTypePanel.class.getName());
@@ -81,7 +85,7 @@ public class MimeTypePanel extends javax.swing.JPanel {
jLabel1 = new javax.swing.JLabel();
setMinimumSize(new java.awt.Dimension(150, 150));
setPreferredSize(new java.awt.Dimension(100, 100));
setPreferredSize(new java.awt.Dimension(150, 150));
mimeTypeList.setModel(new javax.swing.AbstractListModel<String>() {
String[] strings = getMimeTypeArray();
@@ -98,8 +102,8 @@ public class MimeTypePanel extends javax.swing.JPanel {
}
});
org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(MimeTypePanel.class, "MimeTypePanel.jLabel1.text")); // NOI18N
jLabel1.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(MimeTypePanel.class, "MimeTypePanel.jLabel1.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
@@ -122,10 +126,10 @@ public class MimeTypePanel extends javax.swing.JPanel {
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(mimeTypeCheckBox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 94, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 103, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jLabel1)
.addContainerGap())
.addGap(40, 40, 40))
);
}// </editor-fold>//GEN-END:initComponents
@@ -54,14 +54,16 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
<Group type="102" alignment="1" attributes="0">
<Group type="103" groupAlignment="1" attributes="0">
<Component id="noteNameLabel" min="-2" max="-2" attributes="0"/>
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="noteNameLabel" pref="0" max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Component id="nameCheckBox" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="searchTextField" max="32767" attributes="0"/>
<Component id="searchTextField" pref="191" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
@@ -117,9 +119,11 @@
<Font bold="false" component="noteNameLabel" property="font" relativeSize="false" size="10"/>
</FontInfo>
</Property>
<Property name="horizontalAlignment" type="int" value="11"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="NameSearchPanel.noteNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="verticalAlignment" type="int" value="1"/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[250, 30]"/>
</Property>
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* NameSearchPanel.java
*
* Created on Oct 19, 2011, 11:58:53 AM
*/
package org.sleuthkit.autopsy.filesearch;
import java.awt.event.ActionEvent;
@@ -33,9 +27,9 @@ import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
/**
*
* @author pmartel
* Provide a name for search.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class NameSearchPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
@@ -146,7 +140,9 @@ class NameSearchPanel extends javax.swing.JPanel {
searchTextField.setText(org.openide.util.NbBundle.getMessage(NameSearchPanel.class, "NameSearchPanel.searchTextField.text")); // NOI18N
noteNameLabel.setFont(noteNameLabel.getFont().deriveFont(noteNameLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 10));
noteNameLabel.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING);
noteNameLabel.setText(org.openide.util.NbBundle.getMessage(NameSearchPanel.class, "NameSearchPanel.noteNameLabel.text")); // NOI18N
noteNameLabel.setVerticalAlignment(javax.swing.SwingConstants.TOP);
noteNameLabel.setMaximumSize(new java.awt.Dimension(250, 30));
noteNameLabel.setMinimumSize(new java.awt.Dimension(250, 30));
noteNameLabel.setPreferredSize(new java.awt.Dimension(250, 40));
@@ -155,14 +151,15 @@ class NameSearchPanel extends javax.swing.JPanel {
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(0, 0, 0)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(noteNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(noteNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))
.addGroup(layout.createSequentialGroup()
.addComponent(nameCheckBox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(searchTextField)))
.addComponent(searchTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 191, Short.MAX_VALUE)))
.addGap(0, 0, 0))
);
layout.setVerticalGroup(
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -29,9 +29,9 @@ import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
/**
*
* @author pmartel
* Provide file size for search.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class SizeSearchPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
@@ -34,8 +34,6 @@ import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -69,16 +67,14 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
private final static String DATABASE_NAME = "EnterpriseHealthMonitor";
private final static long DATABASE_WRITE_INTERVAL = 60; // Minutes
public static final CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION
= new CaseDbSchemaVersionNumber(1, 0);
= new CaseDbSchemaVersionNumber(1, 1);
private static final AtomicBoolean isEnabled = new AtomicBoolean(false);
private static EnterpriseHealthMonitor instance;
private final ExecutorService healthMonitorExecutor;
private static final String HEALTH_MONITOR_EVENT_THREAD_NAME = "Health-Monitor-Event-Listener-%d";
private ScheduledThreadPoolExecutor healthMonitorOutputTimer;
private final Map<String, TimingInfo> timingInfoMap;
private final List<UserData> userInfoList;
private static final int CONN_POOL_SIZE = 10;
private BasicDataSource connectionPool = null;
private CaseDbConnectionInfo connectionSettingsInUse = null;
@@ -90,8 +86,9 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
// of whether the monitor is enabled.
timingInfoMap = new HashMap<>();
// Set up the executor to handle case events
healthMonitorExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(HEALTH_MONITOR_EVENT_THREAD_NAME).build());
// Create the list to hold user information. The list will exist regardless
// of whether the monitor is enabled.
userInfoList = new ArrayList<>();
// Get the host name
try {
@@ -156,12 +153,70 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
initializeDatabaseSchema();
}
if( ! CURRENT_DB_SCHEMA_VERSION.equals(getVersion())) {
upgradeDatabaseSchema();
}
} catch (CoordinationService.CoordinationServiceException ex) {
throw new HealthMonitorException("Error releasing database lock", ex);
}
// Clear out any old data
timingInfoMap.clear();
userInfoList.clear();
}
/**
* Upgrade an older database
*/
private void upgradeDatabaseSchema() throws HealthMonitorException {
logger.log(Level.INFO, "Upgrading Health Monitor database");
CaseDbSchemaVersionNumber currentSchema = getVersion();
Connection conn = connect();
if(conn == null) {
throw new HealthMonitorException("Error getting database connection");
}
try (Statement statement = conn.createStatement()) {
conn.setAutoCommit(false);
// Upgrade from 1.0 to 1.1
// Changes: user_data table added
if(currentSchema.compareTo(new CaseDbSchemaVersionNumber(1,1)) < 0) {
// Add the user_data table
statement.execute("CREATE TABLE IF NOT EXISTS user_data ("+
"id SERIAL PRIMARY KEY," +
"host text NOT NULL," +
"timestamp bigint NOT NULL," +
"event_type int NOT NULL," +
"is_examiner boolean NOT NULL," +
"case_name text NOT NULL" +
")");
}
// Update the schema version
statement.execute("UPDATE db_info SET value='" + CURRENT_DB_SCHEMA_VERSION.getMajor() + "' WHERE name='SCHEMA_VERSION'");
statement.execute("UPDATE db_info SET value='" + CURRENT_DB_SCHEMA_VERSION.getMinor() + "' WHERE name='SCHEMA_MINOR_VERSION'");
conn.commit();
logger.log(Level.INFO, "Health Monitor database upgraded to version {0}", CURRENT_DB_SCHEMA_VERSION.toString());
} catch (SQLException ex) {
try {
conn.rollback();
} catch (SQLException ex2) {
logger.log(Level.SEVERE, "Rollback error");
}
throw new HealthMonitorException("Error upgrading database", ex);
} finally {
try {
conn.close();
} catch (SQLException ex) {
logger.log(Level.SEVERE, "Error closing connection.", ex);
}
}
}
/**
@@ -190,7 +245,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
stopTimer();
healthMonitorOutputTimer = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat("health_monitor_timer").build());
healthMonitorOutputTimer.scheduleWithFixedDelay(new PeriodicHealthMonitorTask(false), DATABASE_WRITE_INTERVAL, DATABASE_WRITE_INTERVAL, TimeUnit.MINUTES);
healthMonitorOutputTimer.scheduleWithFixedDelay(new PeriodicHealthMonitorTask(), DATABASE_WRITE_INTERVAL, DATABASE_WRITE_INTERVAL, TimeUnit.MINUTES);
}
/**
@@ -207,7 +262,17 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
* @throws HealthMonitorException
*/
static synchronized void startUpIfEnabled() throws HealthMonitorException {
getInstance();
getInstance().addUserEvent(UserEvent.LOG_ON);
}
/**
* Called when the application is closing.
* Create a log off event and write all existing metrics to the database
* @throws HealthMonitorException
*/
static synchronized void shutdown() throws HealthMonitorException {
getInstance().addUserEvent(UserEvent.LOG_OFF);
recordMetrics();
}
/**
@@ -318,6 +383,17 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
}
}
/**
* Add a user event to the list.
* @param eventType
*/
private void addUserEvent(UserEvent eventType) {
UserData userInfo = new UserData(eventType);
synchronized(this) {
userInfoList.add(userInfo);
}
}
/**
* Time a database query.
* Database queries are hard to test in normal processing because the time
@@ -356,16 +432,10 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
/**
* Collect metrics at a scheduled time.
* @param caseIsClosing True if this was triggered from a case closed event
* @throws HealthMonitorException
*/
private void gatherTimerBasedMetrics(boolean caseIsClosing) throws HealthMonitorException {
// Time a database query. If this was triggered from a case close event
// it will fail - since we're on a new thread the case database will
// be in the process of closing. In that case, skip collecting the metric.
if( ! caseIsClosing) {
performDatabaseQuery();
}
private void gatherTimerBasedMetrics() throws HealthMonitorException {
performDatabaseQuery();
}
/**
@@ -375,6 +445,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
private void writeCurrentStateToDatabase() throws HealthMonitorException {
Map<String, TimingInfo> timingMapCopy;
List<UserData> userDataCopy;
// Do as little as possible within the synchronized block since it will
// block threads attempting to record metrics.
@@ -387,10 +458,13 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
// per metric name.
timingMapCopy = new HashMap<>(timingInfoMap);
timingInfoMap.clear();
userDataCopy = new ArrayList<>(userInfoList);
userInfoList.clear();
}
// Check if there's anything to report (right now we only have the timing map)
if(timingMapCopy.keySet().isEmpty()) {
// Check if there's anything to report
if(timingMapCopy.keySet().isEmpty() && userDataCopy.isEmpty()) {
return;
}
@@ -407,22 +481,33 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
throw new HealthMonitorException("Error getting database connection");
}
// Add timing metrics to the database
// Add metrics to the database
String addTimingInfoSql = "INSERT INTO timing_data (name, host, timestamp, count, average, max, min) VALUES (?, ?, ?, ?, ?, ?, ?)";
try (PreparedStatement statement = conn.prepareStatement(addTimingInfoSql)) {
String addUserInfoSql = "INSERT INTO user_data (host, timestamp, event_type, is_examiner, case_name) VALUES (?, ?, ?, ?, ?)";
try (PreparedStatement timingStatement = conn.prepareStatement(addTimingInfoSql);
PreparedStatement userStatement = conn.prepareStatement(addUserInfoSql)) {
for(String name:timingMapCopy.keySet()) {
TimingInfo info = timingMapCopy.get(name);
statement.setString(1, name);
statement.setString(2, hostName);
statement.setLong(3, System.currentTimeMillis());
statement.setLong(4, info.getCount());
statement.setDouble(5, info.getAverage());
statement.setDouble(6, info.getMax());
statement.setDouble(7, info.getMin());
timingStatement.setString(1, name);
timingStatement.setString(2, hostName);
timingStatement.setLong(3, System.currentTimeMillis());
timingStatement.setLong(4, info.getCount());
timingStatement.setDouble(5, info.getAverage());
timingStatement.setDouble(6, info.getMax());
timingStatement.setDouble(7, info.getMin());
statement.execute();
timingStatement.execute();
}
for(UserData userInfo:userDataCopy) {
userStatement.setString(1, hostName);
userStatement.setLong(2, userInfo.getTimestamp());
userStatement.setInt(3, userInfo.getEventType().getEventValue());
userStatement.setBoolean(4, userInfo.isExaminerNode());
userStatement.setString(5, userInfo.getCaseName());
userStatement.execute();
}
} catch (SQLException ex) {
@@ -762,9 +847,8 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
try (Statement statement = conn.createStatement()) {
conn.setAutoCommit(false);
String createTimingTable =
"CREATE TABLE IF NOT EXISTS timing_data (" +
statement.execute("CREATE TABLE IF NOT EXISTS timing_data (" +
"id SERIAL PRIMARY KEY," +
"name text NOT NULL," +
"host text NOT NULL," +
@@ -773,16 +857,23 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
"average double precision NOT NULL," +
"max double precision NOT NULL," +
"min double precision NOT NULL" +
")";
statement.execute(createTimingTable);
")");
String createDbInfoTable =
"CREATE TABLE IF NOT EXISTS db_info (" +
statement.execute("CREATE TABLE IF NOT EXISTS db_info (" +
"id SERIAL PRIMARY KEY NOT NULL," +
"name text NOT NULL," +
"value text NOT NULL" +
")";
statement.execute(createDbInfoTable);
")");
statement.execute("CREATE TABLE IF NOT EXISTS user_data ("+
"id SERIAL PRIMARY KEY," +
"host text NOT NULL," +
"timestamp bigint NOT NULL," +
"event_type int NOT NULL," +
"is_examiner BOOLEAN NOT NULL," +
"case_name text NOT NULL" +
")");
statement.execute("INSERT INTO db_info (name, value) VALUES ('SCHEMA_VERSION', '" + CURRENT_DB_SCHEMA_VERSION.getMajor() + "')");
statement.execute("INSERT INTO db_info (name, value) VALUES ('SCHEMA_MINOR_VERSION', '" + CURRENT_DB_SCHEMA_VERSION.getMinor() + "')");
@@ -807,31 +898,32 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
/**
* The task called by the ScheduledThreadPoolExecutor to handle
* the database checks/writes.
* the periodic database update
*/
static final class PeriodicHealthMonitorTask implements Runnable {
boolean caseIsClosing;
PeriodicHealthMonitorTask(boolean caseIsClosing) {
this.caseIsClosing = caseIsClosing;
}
/**
* Perform all periodic tasks:
* - Check if monitoring has been enabled / disabled in the database
* - Calculate any final metrics
* - Write current metric data to the database
*/
@Override
public void run() {
try {
getInstance().updateFromGlobalEnabledStatus();
getInstance().gatherTimerBasedMetrics(caseIsClosing);
recordMetrics();
}
}
/**
* Perform all periodic tasks:
* - Check if monitoring has been enabled / disabled in the database
* - Gather any additional metrics
* - Write current metric data to the database
* Do not run this from a new thread if the case/application is closing.
*/
private static void recordMetrics() {
try {
getInstance().updateFromGlobalEnabledStatus();
if(monitorIsEnabled()) {
getInstance().gatherTimerBasedMetrics();
getInstance().writeCurrentStateToDatabase();
} catch (HealthMonitorException ex) {
logger.log(Level.SEVERE, "Error performing periodic task", ex); //NON-NLS
}
} catch (HealthMonitorException ex) {
logger.log(Level.SEVERE, "Error performing periodic task", ex); //NON-NLS
}
}
@@ -842,8 +934,12 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
case CURRENT_CASE:
if ((null == evt.getNewValue()) && (evt.getOldValue() instanceof Case)) {
// When a case is closed, write the current metrics to the database
healthMonitorExecutor.submit(new EnterpriseHealthMonitor.PeriodicHealthMonitorTask(true));
// Case is closing
addUserEvent(UserEvent.CASE_CLOSE);
} else if((null == evt.getOldValue()) && (evt.getNewValue() instanceof Case)) {
// Case is opening
addUserEvent(UserEvent.CASE_OPEN);
}
break;
}
@@ -866,7 +962,8 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
throw new HealthMonitorException("Error getting database lock");
}
String[] metricNames = {"Disk Reads: Hash calculation", "Database: getImages query", "Solr: Index chunk", "Solr: Connectivity check"}; // NON-NLS
String[] metricNames = {"Disk Reads: Hash calculation", "Database: getImages query", "Solr: Index chunk", "Solr: Connectivity check",
"Correlation Engine: Notable artifact query", "Correlation Engine: Bulk insert"}; // NON-NLS
Random rand = new Random();
@@ -1057,6 +1154,47 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
}
}
/**
* Get user metrics currently stored in the database.
* @param timeRange Maximum age for returned metrics (in milliseconds)
* @return A list of user metrics
* @throws HealthMonitorException
*/
List<UserData> getUserMetricsFromDatabase(long timeRange) throws HealthMonitorException {
// Make sure the monitor is enabled. It could theoretically get disabled after this
// check but it doesn't seem worth holding a lock to ensure that it doesn't since that
// may slow down ingest.
if(! isEnabled.get()) {
throw new HealthMonitorException("Health Monitor is not enabled");
}
// Calculate the smallest timestamp we should return
long minimumTimestamp = System.currentTimeMillis() - timeRange;
try (CoordinationService.Lock lock = getSharedDbLock()) {
if(lock == null) {
throw new HealthMonitorException("Error getting database lock");
}
List<UserData> resultList = new ArrayList<>();
try (Connection conn = connect();
Statement statement = conn.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT * FROM user_data WHERE timestamp > " + minimumTimestamp)) {
while (resultSet.next()) {
resultList.add(new UserData(resultSet));
}
return resultList;
} catch (SQLException ex) {
throw new HealthMonitorException("Error reading user metrics from database", ex);
}
} catch (CoordinationService.CoordinationServiceException ex) {
throw new HealthMonitorException("Error getting database lock", ex);
}
}
/**
* Get an exclusive lock for the health monitor database.
* Acquire this before creating, initializing, or updating the database schema.
@@ -1096,6 +1234,164 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
}
}
/**
* Types of user events being logged
*/
enum UserEvent {
LOG_ON(0),
LOG_OFF(1),
CASE_OPEN(2),
CASE_CLOSE(3);
int value;
UserEvent(int value) {
this.value = value;
}
/**
* Get the integer value of the event to store in the database.
* @return value corresponding to the event
*/
int getEventValue() {
return value;
}
/**
* Get the UserEvent from the value stored in the database
* @param value
* @return the corresponding UserEvent object
* @throws HealthMonitorException
*/
static UserEvent valueOf(int value) throws HealthMonitorException {
for (UserEvent v : UserEvent.values()) {
if (v.value == value) {
return v;
}
}
throw new HealthMonitorException("Can not create UserEvent from unknown value " + value);
}
/**
* Return whether a case is considered to be open given this event
* as the last recorded event.
* @return true if a case is open, false otherwise
*/
boolean caseIsOpen() {
return(this.equals(CASE_OPEN));
}
/**
* Return whether a user is considered to be logged in given this event
* as the last recorded event.
* @return true if a the user is logged in, false otherwise
*/
boolean userIsLoggedIn() {
// LOG_ON, CASE_OPEN, and CASE_CLOSED events all imply that the user
// is logged in
return( ! this.equals(LOG_OFF));
}
}
/**
* Class holding user metric data.
* Can be used for storing new events or retrieving
* events out of the database.
*/
static class UserData {
private final UserEvent eventType;
private long timestamp;
private final boolean isExaminer;
private final String hostname;
private String caseName;
/**
* Create a new UserData object using the given event type
* and the current settings.
* @param eventType The type of event being recorded
*/
private UserData(UserEvent eventType) {
this.eventType = eventType;
this.timestamp = System.currentTimeMillis();
this.isExaminer = (UserPreferences.SelectedMode.STANDALONE == UserPreferences.getMode());
this.hostname = "";
// If there's a case open, record the name
try {
this.caseName = Case.getCurrentCaseThrows().getDisplayName();
} catch (NoCurrentCaseException ex) {
// It's not an error if there's no case open
this.caseName = "";
}
}
/**
* Create a UserData object from a database result set.
* @param resultSet The result set containing the data
* @throws SQLException
* @throws HealthMonitorException
*/
UserData(ResultSet resultSet) throws SQLException, HealthMonitorException {
this.timestamp = resultSet.getLong("timestamp");
this.hostname = resultSet.getString("host");
this.eventType = UserEvent.valueOf(resultSet.getInt("event_type"));
this.isExaminer = resultSet.getBoolean("is_examiner");
this.caseName = resultSet.getString("case_name");
}
/**
* This should only be used to make a dummy object to use for timestamp
* comparisons.
* @param timestamp
* @return A UserData object with the given timestamp
*/
static UserData createDummyUserData(long timestamp) {
UserData userData = new UserData(UserEvent.CASE_CLOSE);
userData.timestamp = timestamp;
return userData;
}
/**
* Get the timestamp for the event
* @return Timestamp in milliseconds
*/
long getTimestamp() {
return timestamp;
}
/**
* Get the host that created the metric
* @return the host name
*/
String getHostname() {
return hostname;
}
/**
* Get the type of event
* @return the event type
*/
UserEvent getEventType() {
return eventType;
}
/**
* Check whether this node is an examiner node or an auto ingest node
* @return true if it is an examiner node
*/
boolean isExaminerNode() {
return isExaminer;
}
/**
* Get the name of the case for this metric
* @return the case name. Will be the empty string if no case was open.
*/
String getCaseName() {
return caseName;
}
}
/**
* Internal class for collecting timing metrics.
* Instead of storing each TimingMetric, we only store the min and max
@@ -25,6 +25,7 @@ import java.util.Set;
import java.util.HashSet;
import java.util.HashMap;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
@@ -61,13 +62,16 @@ public class HealthMonitorDashboard {
private final static String ADMIN_ACCESS_FILE_PATH = Paths.get(Places.getUserDirectory().getAbsolutePath(), ADMIN_ACCESS_FILE_NAME).toString();
Map<String, List<EnterpriseHealthMonitor.DatabaseTimingResult>> timingData;
List<EnterpriseHealthMonitor.UserData> userData;
private JComboBox<String> dateComboBox = null;
private JComboBox<String> hostComboBox = null;
private JCheckBox hostCheckBox = null;
private JCheckBox showTrendLineCheckBox = null;
private JCheckBox skipOutliersCheckBox = null;
private JPanel graphPanel = null;
private JComboBox<String> timingDateComboBox = null;
private JComboBox<String> timingHostComboBox = null;
private JCheckBox timingHostCheckBox = null;
private JCheckBox timingShowTrendLineCheckBox = null;
private JCheckBox timingSkipOutliersCheckBox = null;
private JPanel timingGraphPanel = null;
private JComboBox<String> userDateComboBox = null;
private JPanel userGraphPanel = null;
private JDialog dialog = null;
private final Container parentWindow;
@@ -78,6 +82,7 @@ public class HealthMonitorDashboard {
*/
public HealthMonitorDashboard(Container parent) {
timingData = new HashMap<>();
userData = new ArrayList<>();
parentWindow = parent;
}
@@ -91,10 +96,12 @@ public class HealthMonitorDashboard {
// Update the enabled status and get the timing data, then create all
// the sub panels.
JPanel timingPanel;
JPanel userPanel;
JPanel adminPanel;
try {
updateData();
timingPanel = createTimingPanel();
userPanel = createUserPanel();
adminPanel = createAdminPanel();
} catch (HealthMonitorException ex) {
logger.log(Level.SEVERE, "Error creating panels for health monitor dashboard", ex);
@@ -109,6 +116,9 @@ public class HealthMonitorDashboard {
// Add the timing panel
mainPanel.add(timingPanel);
// Add the user panel
mainPanel.add(userPanel);
// Add the admin panel if the admin file is present
File adminFile = new File(ADMIN_ACCESS_FILE_PATH);
if(adminFile.exists()) {
@@ -148,6 +158,9 @@ public class HealthMonitorDashboard {
if(EnterpriseHealthMonitor.monitorIsEnabled()) {
// Get a copy of the timing data from the database
timingData = EnterpriseHealthMonitor.getInstance().getTimingMetricsFromDatabase(DateRange.getMaximumTimestampRange());
// Get a copy of the user data from the database
userData = EnterpriseHealthMonitor.getInstance().getUserMetricsFromDatabase(DateRange.getMaximumTimestampRange());
}
}
@@ -185,12 +198,12 @@ public class HealthMonitorDashboard {
timingMetricPanel.add(new JSeparator());
// Create panel to hold graphs
graphPanel = new JPanel();
graphPanel.setLayout(new GridLayout(0,2));
timingGraphPanel = new JPanel();
timingGraphPanel.setLayout(new GridLayout(0,2));
// Update the graph panel, put it in a scroll pane, and add to the timing metric panel
updateTimingMetricGraphs();
JScrollPane scrollPane = new JScrollPane(graphPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
JScrollPane scrollPane = new JScrollPane(timingGraphPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
timingMetricPanel.add(scrollPane);
timingMetricPanel.revalidate();
timingMetricPanel.repaint();
@@ -216,11 +229,11 @@ public class HealthMonitorDashboard {
// Create the combo box for selecting how much data to display
String[] dateOptionStrings = Arrays.stream(DateRange.values()).map(e -> e.getLabel()).toArray(String[]::new);
dateComboBox = new JComboBox<>(dateOptionStrings);
dateComboBox.setSelectedItem(DateRange.ONE_DAY.getLabel());
timingDateComboBox = new JComboBox<>(dateOptionStrings);
timingDateComboBox.setSelectedItem(DateRange.ONE_DAY.getLabel());
// Set up the listener on the date combo box
dateComboBox.addActionListener(new ActionListener() {
timingDateComboBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
try {
@@ -240,14 +253,14 @@ public class HealthMonitorDashboard {
}
// Load the host names into the combo box
hostComboBox = new JComboBox<>(hostNameSet.toArray(new String[hostNameSet.size()]));
timingHostComboBox = new JComboBox<>(hostNameSet.toArray(new String[hostNameSet.size()]));
// Set up the listener on the combo box
hostComboBox.addActionListener(new ActionListener() {
timingHostComboBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
try {
if((hostCheckBox != null) && hostCheckBox.isSelected()) {
if((timingHostCheckBox != null) && timingHostCheckBox.isSelected()) {
updateTimingMetricGraphs();
}
} catch (HealthMonitorException ex) {
@@ -257,16 +270,16 @@ public class HealthMonitorDashboard {
});
// Create the host checkbox
hostCheckBox = new JCheckBox(Bundle.HealthMonitorDashboard_createTimingControlPanel_filterByHost());
hostCheckBox.setSelected(false);
hostComboBox.setEnabled(false);
timingHostCheckBox = new JCheckBox(Bundle.HealthMonitorDashboard_createTimingControlPanel_filterByHost());
timingHostCheckBox.setSelected(false);
timingHostComboBox.setEnabled(false);
// Set up the listener on the checkbox
hostCheckBox.addActionListener(new ActionListener() {
timingHostCheckBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
try {
hostComboBox.setEnabled(hostCheckBox.isSelected());
timingHostComboBox.setEnabled(timingHostCheckBox.isSelected());
updateTimingMetricGraphs();
} catch (HealthMonitorException ex) {
logger.log(Level.SEVERE, "Error populating timing metric panel", ex);
@@ -275,11 +288,11 @@ public class HealthMonitorDashboard {
});
// Create the checkbox for showing the trend line
showTrendLineCheckBox = new JCheckBox(Bundle.HealthMonitorDashboard_createTimingControlPanel_showTrendLine());
showTrendLineCheckBox.setSelected(true);
timingShowTrendLineCheckBox = new JCheckBox(Bundle.HealthMonitorDashboard_createTimingControlPanel_showTrendLine());
timingShowTrendLineCheckBox.setSelected(true);
// Set up the listener on the checkbox
showTrendLineCheckBox.addActionListener(new ActionListener() {
timingShowTrendLineCheckBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
try {
@@ -291,11 +304,11 @@ public class HealthMonitorDashboard {
});
// Create the checkbox for omitting outliers
skipOutliersCheckBox = new JCheckBox(Bundle.HealthMonitorDashboard_createTimingControlPanel_skipOutliers());
skipOutliersCheckBox.setSelected(false);
timingSkipOutliersCheckBox = new JCheckBox(Bundle.HealthMonitorDashboard_createTimingControlPanel_skipOutliers());
timingSkipOutliersCheckBox.setSelected(false);
// Set up the listener on the checkbox
skipOutliersCheckBox.addActionListener(new ActionListener() {
timingSkipOutliersCheckBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
try {
@@ -308,26 +321,26 @@ public class HealthMonitorDashboard {
// Add the date range combo box and label to the panel
timingControlPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createTimingControlPanel_maxDays()));
timingControlPanel.add(dateComboBox);
timingControlPanel.add(timingDateComboBox);
// Put some space between the elements
timingControlPanel.add(Box.createHorizontalStrut(100));
// Add the host combo box and checkbox to the panel
timingControlPanel.add(hostCheckBox);
timingControlPanel.add(hostComboBox);
timingControlPanel.add(timingHostCheckBox);
timingControlPanel.add(timingHostComboBox);
// Put some space between the elements
timingControlPanel.add(Box.createHorizontalStrut(100));
// Add the skip outliers checkbox
timingControlPanel.add(this.showTrendLineCheckBox);
timingControlPanel.add(this.timingShowTrendLineCheckBox);
// Put some space between the elements
timingControlPanel.add(Box.createHorizontalStrut(100));
// Add the skip outliers checkbox
timingControlPanel.add(this.skipOutliersCheckBox);
timingControlPanel.add(this.timingSkipOutliersCheckBox);
return timingControlPanel;
}
@@ -340,11 +353,11 @@ public class HealthMonitorDashboard {
private void updateTimingMetricGraphs() throws HealthMonitorException {
// Clear out any old graphs
graphPanel.removeAll();
timingGraphPanel.removeAll();
if(timingData.keySet().isEmpty()) {
// There are no timing metrics in the database
graphPanel.add(new JLabel(Bundle.HealthMonitorDashboard_updateTimingMetricGraphs_noData()));
timingGraphPanel.add(new JLabel(Bundle.HealthMonitorDashboard_updateTimingMetricGraphs_noData()));
return;
}
@@ -352,8 +365,8 @@ public class HealthMonitorDashboard {
// If necessary, trim down the list of results to fit the selected time range
List<EnterpriseHealthMonitor.DatabaseTimingResult> intermediateTimingDataForDisplay;
if(dateComboBox.getSelectedItem() != null) {
DateRange selectedDateRange = DateRange.fromLabel(dateComboBox.getSelectedItem().toString());
if(timingDateComboBox.getSelectedItem() != null) {
DateRange selectedDateRange = DateRange.fromLabel(timingDateComboBox.getSelectedItem().toString());
long threshold = System.currentTimeMillis() - selectedDateRange.getTimestampRange();
intermediateTimingDataForDisplay = timingData.get(metricName).stream()
.filter(t -> t.getTimestamp() > threshold)
@@ -366,25 +379,150 @@ public class HealthMonitorDashboard {
// The graph always uses the data from all hosts to generate the x and y scales
// so we don't filter anything out here.
String hostToDisplay = null;
if(hostCheckBox.isSelected() && (hostComboBox.getSelectedItem() != null)) {
hostToDisplay = hostComboBox.getSelectedItem().toString();
if(timingHostCheckBox.isSelected() && (timingHostComboBox.getSelectedItem() != null)) {
hostToDisplay = timingHostComboBox.getSelectedItem().toString();
}
// Generate the graph
TimingMetricGraphPanel singleTimingGraphPanel = new TimingMetricGraphPanel(intermediateTimingDataForDisplay,
hostToDisplay, true, metricName, skipOutliersCheckBox.isSelected(), showTrendLineCheckBox.isSelected());
hostToDisplay, true, metricName, timingSkipOutliersCheckBox.isSelected(), timingShowTrendLineCheckBox.isSelected());
singleTimingGraphPanel.setPreferredSize(new Dimension(700,200));
graphPanel.add(singleTimingGraphPanel);
timingGraphPanel.add(singleTimingGraphPanel);
}
graphPanel.revalidate();
graphPanel.repaint();
timingGraphPanel.revalidate();
timingGraphPanel.repaint();
}
/**
* Create the user panel.
* This displays cases open and users logged in
* @return the user panel
*/
@NbBundle.Messages({"HealthMonitorDashboard.createUserPanel.noData=No data to display - monitor is not enabled",
"HealthMonitorDashboard.createUserPanel.userMetricsTitle=User Metrics"})
private JPanel createUserPanel() throws HealthMonitorException {
// If the monitor isn't enabled, just add a message
if(! EnterpriseHealthMonitor.monitorIsEnabled()) {
JPanel emptyUserMetricPanel = new JPanel();
emptyUserMetricPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createUserPanel_userMetricsTitle()));
emptyUserMetricPanel.add(new JLabel(" "));
emptyUserMetricPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createUserPanel_noData()));
return emptyUserMetricPanel;
}
JPanel userMetricPanel = new JPanel();
userMetricPanel.setLayout(new BoxLayout(userMetricPanel, BoxLayout.PAGE_AXIS));
userMetricPanel.setBorder(BorderFactory.createEtchedBorder());
// Add title
JLabel userMetricTitle = new JLabel(Bundle.HealthMonitorDashboard_createUserPanel_userMetricsTitle());
userMetricPanel.add(userMetricTitle);
userMetricPanel.add(new JSeparator());
// Add the controls
userMetricPanel.add(createUserControlPanel());
userMetricPanel.add(new JSeparator());
// Create panel to hold graphs
userGraphPanel = new JPanel();
userGraphPanel.setLayout(new GridLayout(0,2));
// Update the graph panel, put it in a scroll pane, and add to the timing metric panel
updateUserMetricGraphs();
JScrollPane scrollPane = new JScrollPane(userGraphPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
userMetricPanel.add(scrollPane);
userMetricPanel.revalidate();
userMetricPanel.repaint();
return userMetricPanel;
}
/**
* Create the panel with controls for the user panel
* @return the control panel
*/
@NbBundle.Messages({"HealthMonitorDashboard.createUserControlPanel.maxDays=Max days to display"})
private JPanel createUserControlPanel() {
JPanel userControlPanel = new JPanel();
// If the monitor is not enabled, don't add any components
if(! EnterpriseHealthMonitor.monitorIsEnabled()) {
return userControlPanel;
}
// Create the combo box for selecting how much data to display
String[] dateOptionStrings = Arrays.stream(DateRange.values()).map(e -> e.getLabel()).toArray(String[]::new);
userDateComboBox = new JComboBox<>(dateOptionStrings);
userDateComboBox.setSelectedItem(DateRange.ONE_DAY.getLabel());
// Set up the listener on the date combo box
userDateComboBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
try {
updateUserMetricGraphs();
} catch (HealthMonitorException ex) {
logger.log(Level.SEVERE, "Error updating user metric panel", ex);
}
}
});
// Add the date range combo box and label to the panel
userControlPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createUserControlPanel_maxDays()));
userControlPanel.add(userDateComboBox);
return userControlPanel;
}
/**
* Update the user graphs.
* @throws HealthMonitorException
*/
@NbBundle.Messages({"HealthMonitorDashboard.updateUserMetricGraphs.noData=No data to display"})
private void updateUserMetricGraphs() throws HealthMonitorException {
// Clear out any old graphs
userGraphPanel.removeAll();
if(userData.isEmpty()) {
// There are no user metrics in the database
userGraphPanel.add(new JLabel(Bundle.HealthMonitorDashboard_updateUserMetricGraphs_noData()));
return;
}
// Calculate the minimum timestamp for the graph.
// Unlike the timing graphs, we do not filter the list of user metrics here.
// This is because even if we're only displaying one day, the
// last metric for a host may be that it logged on two days ago, so we would want
// to show that node as logged on.
long timestampThreshold;
if(userDateComboBox.getSelectedItem() != null) {
DateRange selectedDateRange = DateRange.fromLabel(userDateComboBox.getSelectedItem().toString());
timestampThreshold = System.currentTimeMillis() - selectedDateRange.getTimestampRange();
} else {
timestampThreshold = System.currentTimeMillis() - DateRange.getMaximumTimestampRange();
}
// Generate the graphs
UserMetricGraphPanel caseGraphPanel = new UserMetricGraphPanel(userData, timestampThreshold, true);
caseGraphPanel.setPreferredSize(new Dimension(700,200));
UserMetricGraphPanel logonGraphPanel = new UserMetricGraphPanel(userData, timestampThreshold, false);
logonGraphPanel.setPreferredSize(new Dimension(700,200));
userGraphPanel.add(caseGraphPanel);
userGraphPanel.add(logonGraphPanel);
userGraphPanel.revalidate();
userGraphPanel.repaint();
}
/**
* Create the admin panel.
* This allows the health monitor to be enabled and disabled.
* @return
* @return the admin panel
*/
@NbBundle.Messages({"HealthMonitorDashboard.createAdminPanel.enableButton=Enable monitor",
"HealthMonitorDashboard.createAdminPanel.disableButton=Disable monitor"})

Some files were not shown because too many files have changed in this diff Show More