mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-14 17:06:16 +00:00
Merge pull request #7240 from eugene7646/new_cr_artifacts
Merged develop and resolved conflicts
This commit is contained in:
commit
e74d948572
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2017 Basis Technology Corp.
|
||||
* Copyright 2011-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -43,6 +43,7 @@ import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
||||
import org.sleuthkit.autopsy.coreutils.Version;
|
||||
import org.sleuthkit.autopsy.guiutils.JFileChooserFactory;
|
||||
|
||||
/**
|
||||
* The action associated with the Case/Open Case menu item via the layer.xml
|
||||
@ -64,6 +65,8 @@ public final class CaseOpenAction extends CallableSystemAction implements Action
|
||||
private static final Logger LOGGER = Logger.getLogger(CaseOpenAction.class.getName());
|
||||
private final FileFilter caseMetadataFileFilter;
|
||||
|
||||
private final JFileChooserFactory fileChooserHelper;
|
||||
|
||||
/**
|
||||
* Constructs the action associated with the Case/Open Case menu item via
|
||||
* the layer.xml file, a toolbar button, and the Open Case button of the
|
||||
@ -72,6 +75,7 @@ public final class CaseOpenAction extends CallableSystemAction implements Action
|
||||
*/
|
||||
public CaseOpenAction() {
|
||||
caseMetadataFileFilter = new FileNameExtensionFilter(NbBundle.getMessage(CaseOpenAction.class, "CaseOpenAction.autFilter.title", Version.getName(), CaseMetadata.getFileExtension()), CaseMetadata.getFileExtension().substring(1));
|
||||
fileChooserHelper = new JFileChooserFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -80,7 +84,7 @@ public final class CaseOpenAction extends CallableSystemAction implements Action
|
||||
* to open the case described by the file.
|
||||
*/
|
||||
void openCaseSelectionWindow() {
|
||||
JFileChooser fileChooser = new JFileChooser();
|
||||
JFileChooser fileChooser = fileChooserHelper.getChooser();
|
||||
fileChooser.setDragEnabled(false);
|
||||
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||
fileChooser.setMultiSelectionEnabled(false);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2018 Basis Technology Corp.
|
||||
* Copyright 2011-2021 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.DriveUtils;
|
||||
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
||||
import org.sleuthkit.autopsy.coreutils.PathValidator;
|
||||
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
|
||||
import org.sleuthkit.autopsy.guiutils.JFileChooserFactory;
|
||||
import org.sleuthkit.datamodel.HashUtility;
|
||||
|
||||
/**
|
||||
@ -48,8 +49,10 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String PROP_LASTIMAGE_PATH = "LBL_LastImage_PATH"; //NON-NLS
|
||||
private static final String[] SECTOR_SIZE_CHOICES = {"Auto Detect", "512", "1024", "2048", "4096"};
|
||||
private final JFileChooser fileChooser = new JFileChooser();
|
||||
private final JFileChooserFactory fileChooserHelper = new JFileChooserFactory();
|
||||
private JFileChooser fileChooser;
|
||||
private final String contextName;
|
||||
private final List<FileFilter> fileChooserFilters;
|
||||
|
||||
/**
|
||||
* Creates new form ImageFilePanel
|
||||
@ -73,14 +76,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
|
||||
sectorSizeComboBox.setSelectedIndex(0);
|
||||
|
||||
errorLabel.setVisible(false);
|
||||
|
||||
fileChooser.setDragEnabled(false);
|
||||
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||
fileChooser.setMultiSelectionEnabled(false);
|
||||
fileChooserFilters.forEach(fileChooser::addChoosableFileFilter);
|
||||
if (fileChooserFilters.isEmpty() == false) {
|
||||
fileChooser.setFileFilter(fileChooserFilters.get(0));
|
||||
}
|
||||
this.fileChooserFilters = fileChooserFilters;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -133,6 +129,21 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
|
||||
return sha256HashTextField;
|
||||
}
|
||||
|
||||
private JFileChooser getChooser() {
|
||||
if(fileChooser == null) {
|
||||
fileChooser = fileChooserHelper.getChooser();
|
||||
fileChooser.setDragEnabled(false);
|
||||
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||
fileChooser.setMultiSelectionEnabled(false);
|
||||
fileChooserFilters.forEach(fileChooser::addChoosableFileFilter);
|
||||
if (fileChooserFilters.isEmpty() == false) {
|
||||
fileChooser.setFileFilter(fileChooserFilters.get(0));
|
||||
}
|
||||
}
|
||||
|
||||
return fileChooser;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@ -298,12 +309,13 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
|
||||
String oldText = getContentPaths();
|
||||
// set the current directory of the FileChooser if the ImagePath Field is valid
|
||||
File currentDir = new File(oldText);
|
||||
JFileChooser chooser = getChooser();
|
||||
if (currentDir.exists()) {
|
||||
fileChooser.setCurrentDirectory(currentDir);
|
||||
chooser.setCurrentDirectory(currentDir);
|
||||
}
|
||||
|
||||
if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
|
||||
String path = fileChooser.getSelectedFile().getPath();
|
||||
if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
|
||||
String path = chooser.getSelectedFile().getPath();
|
||||
if (path.endsWith(".001")) {
|
||||
String zeroX3_path = StringUtils.removeEnd(path, ".001") + ".000";
|
||||
if (new File(zeroX3_path).exists()) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2018 Basis Technology Corp.
|
||||
* Copyright 2011-2021 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.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
||||
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
|
||||
import org.sleuthkit.autopsy.guiutils.JFileChooserFactory;
|
||||
import org.sleuthkit.autopsy.imagewriter.ImageWriterSettings;
|
||||
|
||||
/**
|
||||
@ -58,7 +59,8 @@ final class LocalDiskPanel extends JPanel {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private LocalDisk localDisk;
|
||||
private boolean enableNext = false;
|
||||
private final JFileChooser fc = new JFileChooser();
|
||||
private JFileChooser fc;
|
||||
private final JFileChooserFactory chooserHelper;
|
||||
|
||||
/**
|
||||
* Creates new form LocalDiskPanel
|
||||
@ -68,6 +70,7 @@ final class LocalDiskPanel extends JPanel {
|
||||
customInit();
|
||||
createTimeZoneList();
|
||||
createSectorSizeList();
|
||||
chooserHelper = new JFileChooserFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -261,6 +264,7 @@ final class LocalDiskPanel extends JPanel {
|
||||
}//GEN-LAST:event_pathTextFieldKeyReleased
|
||||
|
||||
private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed
|
||||
fc = chooserHelper.getChooser();
|
||||
String oldText = pathTextField.getText();
|
||||
// set the current directory of the FileChooser if the ImagePath Field is valid
|
||||
File currentFile = new File(oldText);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2012-2018 Basis Technology Corp.
|
||||
* Copyright 2012-2021 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.util.NbBundle;
|
||||
import org.openide.windows.WindowManager;
|
||||
import org.sleuthkit.autopsy.coreutils.DriveUtils;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.guiutils.JFileChooserFactory;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
@ -45,7 +46,8 @@ class MissingImageDialog extends javax.swing.JDialog {
|
||||
long obj_id;
|
||||
SleuthkitCase db;
|
||||
|
||||
private final JFileChooser fileChooser = new JFileChooser();
|
||||
private JFileChooser fileChooser;
|
||||
private final JFileChooserFactory chooserHelper;
|
||||
|
||||
/**
|
||||
* Instantiate a MissingImageDialog.
|
||||
@ -59,16 +61,7 @@ class MissingImageDialog extends javax.swing.JDialog {
|
||||
this.db = db;
|
||||
initComponents();
|
||||
|
||||
fileChooser.setDragEnabled(false);
|
||||
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||
fileChooser.setMultiSelectionEnabled(false);
|
||||
|
||||
List<FileFilter> fileFiltersList = ImageDSProcessor.getFileFiltersList();
|
||||
for (FileFilter fileFilter : fileFiltersList) {
|
||||
fileChooser.addChoosableFileFilter(fileFilter);
|
||||
}
|
||||
fileChooser.setFileFilter(fileFiltersList.get(0));
|
||||
|
||||
chooserHelper = new JFileChooserFactory();
|
||||
selectButton.setEnabled(false);
|
||||
}
|
||||
|
||||
@ -270,6 +263,19 @@ class MissingImageDialog extends javax.swing.JDialog {
|
||||
|
||||
private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed
|
||||
|
||||
if(fileChooser == null) {
|
||||
fileChooser = chooserHelper.getChooser();
|
||||
fileChooser.setDragEnabled(false);
|
||||
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||
fileChooser.setMultiSelectionEnabled(false);
|
||||
|
||||
List<FileFilter> fileFiltersList = ImageDSProcessor.getFileFiltersList();
|
||||
for (FileFilter fileFilter : fileFiltersList) {
|
||||
fileChooser.addChoosableFileFilter(fileFilter);
|
||||
}
|
||||
fileChooser.setFileFilter(fileFiltersList.get(0));
|
||||
}
|
||||
|
||||
String oldText = pathNameTextField.getText();
|
||||
lbWarning.setText("");
|
||||
// set the current directory of the FileChooser if the ImagePath Field is valid
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2020 Basis Technology Corp.
|
||||
* Copyright 2011-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -30,6 +30,7 @@ import javax.swing.event.DocumentListener;
|
||||
import org.sleuthkit.autopsy.casemodule.Case.CaseType;
|
||||
import org.sleuthkit.autopsy.coreutils.PathValidator;
|
||||
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
||||
import org.sleuthkit.autopsy.guiutils.JFileChooserFactory;
|
||||
|
||||
/**
|
||||
* The JPanel for the first page of the new case wizard.
|
||||
@ -37,7 +38,7 @@ import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
||||
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
||||
final class NewCaseVisualPanel1 extends JPanel implements DocumentListener {
|
||||
|
||||
private final JFileChooser fileChooser = new JFileChooser();
|
||||
private final JFileChooserFactory fileChooserHelper = new JFileChooserFactory();
|
||||
private final NewCaseWizardPanel1 wizPanel;
|
||||
|
||||
/**
|
||||
@ -353,8 +354,9 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener {
|
||||
* @param evt the action event
|
||||
*/
|
||||
private void caseDirBrowseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_caseDirBrowseButtonActionPerformed
|
||||
JFileChooser fileChooser = fileChooserHelper.getChooser();
|
||||
fileChooser.setDragEnabled(false);
|
||||
if (!caseParentDirTextField.getText().trim().equals("")) {
|
||||
if (!caseParentDirTextField.getText().trim().isEmpty()) {
|
||||
fileChooser.setCurrentDirectory(new File(caseParentDirTextField.getText()));
|
||||
}
|
||||
fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2019 Basis Technology Corp.
|
||||
* Copyright 2019-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -88,26 +88,9 @@ public final class OtherOccurrences {
|
||||
if (osAccountAddr.isPresent()) {
|
||||
try {
|
||||
for (OsAccountInstance instance : osAccount.getOsAccountInstances()) {
|
||||
DataSource osAccountDataSource = instance.getDataSource();
|
||||
try {
|
||||
CorrelationCase correlationCase = CentralRepository.getInstance().getCase(Case.getCurrentCaseThrows());
|
||||
CorrelationAttributeInstance correlationAttributeInstance = new CorrelationAttributeInstance(
|
||||
CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.OSACCOUNT_TYPE_ID),
|
||||
osAccountAddr.get(),
|
||||
correlationCase,
|
||||
CorrelationDataSource.fromTSKDataSource(correlationCase, instance.getDataSource()),
|
||||
"",
|
||||
"",
|
||||
TskData.FileKnown.KNOWN,
|
||||
osAccount.getId());
|
||||
|
||||
CorrelationAttributeInstance correlationAttributeInstance = CorrelationAttributeUtil.makeCorrAttr(instance.getOsAccount(), instance.getDataSource());
|
||||
if (correlationAttributeInstance != null) {
|
||||
ret.add(correlationAttributeInstance);
|
||||
} catch (CentralRepoException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Cannot get central repository for OsAccount: %s.", osAccountAddr.get()), ex); //NON-NLS
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
logger.log(Level.WARNING, String.format("Exception while getting open case looking up osAccount %s.", osAccountAddr.get()), ex); //NON-NLS
|
||||
} catch (CorrelationAttributeNormalizationException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Exception with Correlation Attribute Normalization for osAccount %s.", osAccountAddr.get()), ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
|
@ -40,6 +40,8 @@ import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.DataArtifact;
|
||||
import org.sleuthkit.datamodel.HashUtility;
|
||||
import org.sleuthkit.datamodel.InvalidAccountIDException;
|
||||
import org.sleuthkit.datamodel.OsAccount;
|
||||
import org.sleuthkit.datamodel.OsAccountInstance;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
@ -568,6 +570,51 @@ public class CorrelationAttributeUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a correlation attribute instance of a given type from an OS
|
||||
* account. Checks address if it is null, or one of the ones always present
|
||||
* on a windows system and thus not unique.
|
||||
*
|
||||
* @param osAccoun The OS account.
|
||||
* @param dataSource The data source content object.
|
||||
*
|
||||
* @return The correlation attribute instance or null, if an error occurred.
|
||||
*/
|
||||
public static CorrelationAttributeInstance makeCorrAttr(OsAccount osAccount, Content dataSource) {
|
||||
|
||||
Optional<String> accountAddr = osAccount.getAddr();
|
||||
// Check address if it is null or one of the ones below we want to ignore it since they will always be one a windows system
|
||||
// and they are not unique
|
||||
if (!accountAddr.isPresent() || accountAddr.get().equals("S-1-5-18") || accountAddr.get().equals("S-1-5-19") || accountAddr.get().equals("S-1-5-20")) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
|
||||
CorrelationCase correlationCase = CentralRepository.getInstance().getCase(Case.getCurrentCaseThrows());
|
||||
CorrelationAttributeInstance correlationAttributeInstance = new CorrelationAttributeInstance(
|
||||
CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.OSACCOUNT_TYPE_ID),
|
||||
accountAddr.get(),
|
||||
correlationCase,
|
||||
CorrelationDataSource.fromTSKDataSource(correlationCase, dataSource),
|
||||
"",
|
||||
"",
|
||||
TskData.FileKnown.KNOWN,
|
||||
osAccount.getId());
|
||||
|
||||
return correlationAttributeInstance;
|
||||
|
||||
} catch (CentralRepoException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Cannot get central repository for OsAccount: %s.", accountAddr.get()), ex); //NON-NLS
|
||||
return null;
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
|
||||
return null;
|
||||
} catch (CorrelationAttributeNormalizationException ex) {
|
||||
logger.log(Level.SEVERE, "Exception with Correlation Attribute Normalization.", ex); //NON-NLS
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the correlation attribute instance for a file.
|
||||
*
|
||||
|
@ -664,7 +664,8 @@ public final class CaseEventListener implements PropertyChangeListener {
|
||||
"CaseEventsListener.prevCaseComment.text=Users seen in previous cases",
|
||||
"CaseEventsListener.prevExists.text=Previously Seen Users (Central Repository)"})
|
||||
/**
|
||||
* Add OsAccount Instance to CR and find interesting items based on the OsAccount
|
||||
* Add OsAccount Instance to CR and find interesting items based on the
|
||||
* OsAccount
|
||||
*/
|
||||
private final class OsAccountInstancesAddedTask implements Runnable {
|
||||
|
||||
@ -690,27 +691,15 @@ public final class CaseEventListener implements PropertyChangeListener {
|
||||
for (OsAccountInstance osAccountInstance : addedOsAccountNew) {
|
||||
try {
|
||||
OsAccount osAccount = osAccountInstance.getOsAccount();
|
||||
Optional<String> accountAddr = osAccount.getAddr();
|
||||
// Check address if it is null or one of the ones below we want to ignore it since they will always be one a windows system
|
||||
// and they are not unique
|
||||
if (!accountAddr.isPresent() || accountAddr.get().equals("S-1-5-18") || accountAddr.get().equals("S-1-5-19") || accountAddr.get().equals("S-1-5-20")) {
|
||||
CorrelationAttributeInstance correlationAttributeInstance = CorrelationAttributeUtil.makeCorrAttr(osAccount, osAccountInstance.getDataSource());
|
||||
if (correlationAttributeInstance == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Optional<String> accountAddr = osAccount.getAddr();
|
||||
try {
|
||||
|
||||
CorrelationCase correlationCase = CentralRepository.getInstance().getCase(Case.getCurrentCaseThrows());
|
||||
CorrelationAttributeInstance correlationAttributeInstance = new CorrelationAttributeInstance(
|
||||
CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.OSACCOUNT_TYPE_ID),
|
||||
accountAddr.get(),
|
||||
correlationCase,
|
||||
CorrelationDataSource.fromTSKDataSource(correlationCase, osAccountInstance.getDataSource()),
|
||||
"",
|
||||
"",
|
||||
TskData.FileKnown.KNOWN,
|
||||
osAccount.getId());
|
||||
|
||||
// Save to the database if requested
|
||||
if(IngestEventsListener.shouldCreateCrProperties()) {
|
||||
if (IngestEventsListener.shouldCreateCrProperties()) {
|
||||
dbManager.addArtifactInstance(correlationAttributeInstance);
|
||||
}
|
||||
|
||||
@ -766,14 +755,11 @@ public final class CaseEventListener implements PropertyChangeListener {
|
||||
}
|
||||
}
|
||||
|
||||
} catch (CentralRepoException ex) {
|
||||
LOGGER.log(Level.SEVERE, String.format("Cannot get central repository for OsAccount: %s.", accountAddr.get()), ex); //NON-NLS
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
|
||||
} catch (CorrelationAttributeNormalizationException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Exception with Correlation Attribute Normalization.", ex); //NON-NLS
|
||||
} catch (CentralRepoException ex) {
|
||||
LOGGER.log(Level.SEVERE, String.format("Cannot get central repository for OsAccount: %s.", accountAddr.get()), ex); //NON-NLS
|
||||
}
|
||||
|
||||
} catch (TskCoreException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Cannot get central repository for OsAccount: " + "OsAccount", ex);
|
||||
}
|
||||
|
@ -75,6 +75,7 @@ import org.sleuthkit.datamodel.TskData;
|
||||
*/
|
||||
@NbBundle.Messages({"IngestEventsListener.ingestmodule.name=Central Repository"})
|
||||
public class IngestEventsListener {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(CorrelationAttributeInstance.class.getName());
|
||||
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_COMPLETED);
|
||||
private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(DATA_ADDED);
|
||||
@ -513,8 +514,8 @@ public class IngestEventsListener {
|
||||
try {
|
||||
dataSource = ((DataSourceAnalysisEvent) event).getDataSource();
|
||||
/*
|
||||
* We only care about Images for the purpose of
|
||||
* updating hash values.
|
||||
* We only care about Images for the purpose of updating hash
|
||||
* values.
|
||||
*/
|
||||
if (!(dataSource instanceof Image)) {
|
||||
return;
|
||||
|
@ -13,4 +13,3 @@ IngestSettingsPanel.createCorrelationPropertiesCheckbox.text=\u30a2\u30a4\u30c6\
|
||||
IngestSettingsPanel.flagPreviouslySeenDevicesCheckbox.text=\u4ee5\u524d\u306e\u30b1\u30fc\u30b9\u3067\u898b\u3089\u308c\u305f\u30c7\u30d0\u30a4\u30b9\u306b\u30d5\u30e9\u30b0\u3092\u4ed8\u3051\u308b
|
||||
IngestSettingsPanel.flagTaggedNotableItemsCheckbox.text=\u4ee5\u524d\u306b\u6ce8\u76ee\u3059\u3079\u304d\u30bf\u30b0\u4ed8\u3051\u305f\u30a2\u30a4\u30c6\u30e0\u306b\u30d5\u30e9\u30b0\u3092\u4ed8\u3051\u308b
|
||||
IngestSettingsPanel.ingestSettingsLabel.text=\u53d6\u8fbc\u307f\u8a2d\u5b9a
|
||||
IngestSettingsPanel.flagUniqueAppsCheckbox.text=\u4ee5\u524d\u306e\u30b1\u30fc\u30b9\u3067\u898b\u3089\u308c\u305f\u30c7\u30d0\u30a4\u30b9\u306b\u30d5\u30e9\u30b0\u3092\u4ed8\u3051\u308b
|
||||
|
@ -1,8 +1,9 @@
|
||||
CommandLineIngestSettingPanel_empty_report_name_mgs=Report profile name was empty, no profile created.
|
||||
CommandLineIngestSettingPanel_existing_report_name_mgs=Report profile name was already exists, no profile created.
|
||||
CommandLineIngestSettingPanel_invalid_report_name_mgs=Report profile name contained illegal characters, no profile created.
|
||||
CommandListIngestSettingsPanel_Default_Report_DisplayName=Default
|
||||
CommandListIngestSettingsPanel_Make_Config=Make new profile...
|
||||
CommandListIngestSettingsPanel_Report_Name_Msg=Please supply a report profile name (commas not allowed):
|
||||
CommandListIngestSettingsPanel_Report_Name_Msg=Please supply a report profile name (letters, digits, and underscore characters only):
|
||||
OpenIDE-Module-Name=CommandLineAutopsy
|
||||
OptionsCategory_Keywords_Command_Line_Ingest_Settings=Command Line Ingest Settings
|
||||
OptionsCategory_Keywords_General=Options
|
||||
|
@ -280,19 +280,16 @@ public class CommandLineIngestSettingsPanel extends javax.swing.JPanel {
|
||||
add(nodePanel, java.awt.BorderLayout.CENTER);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
@Messages({
|
||||
"CommandListIngestSettingsPanel_Report_Name_Msg=Please supply a report profile name (commas not allowed):",
|
||||
"CommandListIngestSettingsPanel_Report_Name_Msg=Please supply a report profile name (letters, digits, and underscore characters only):",
|
||||
"CommandLineIngestSettingPanel_empty_report_name_mgs=Report profile name was empty, no profile created.",
|
||||
"CommandLineIngestSettingPanel_existing_report_name_mgs=Report profile name was already exists, no profile created."
|
||||
"CommandLineIngestSettingPanel_existing_report_name_mgs=Report profile name was already exists, no profile created.",
|
||||
"CommandLineIngestSettingPanel_invalid_report_name_mgs=Report profile name contained illegal characters, no profile created."
|
||||
})
|
||||
private void bnEditReportSettingsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnEditReportSettingsActionPerformed
|
||||
String reportName = getReportName();
|
||||
if (reportName.equals(Bundle.CommandListIngestSettingsPanel_Make_Config())) {
|
||||
reportName = JOptionPane.showInputDialog(this, Bundle.CommandListIngestSettingsPanel_Report_Name_Msg());
|
||||
|
||||
// sanitize report name. Remove all commas because in CommandLineOptionProcessor we use commas
|
||||
// to separate multiple report names
|
||||
reportName = reportName.replaceAll(",", "");
|
||||
|
||||
// User hit cancel
|
||||
if (reportName == null) {
|
||||
return;
|
||||
@ -302,6 +299,15 @@ public class CommandLineIngestSettingsPanel extends javax.swing.JPanel {
|
||||
} else if (doesReportProfileNameExist(reportName)) {
|
||||
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), Bundle.CommandLineIngestSettingPanel_existing_report_name_mgs());
|
||||
return;
|
||||
} else {
|
||||
// sanitize report name
|
||||
String originalReportName = reportName;
|
||||
reportName = reportName.replaceAll("[^A-Za-z0-9_]", "");
|
||||
if (reportName.isEmpty() || (!(originalReportName.equals(reportName)))) {
|
||||
// report name contained only invalid characters, display error
|
||||
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), Bundle.CommandLineIngestSettingPanel_invalid_report_name_mgs());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ import java.awt.KeyboardFocusManager;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
@ -38,6 +39,7 @@ import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.communications.ModifiableProxyLookup;
|
||||
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
@ -46,8 +48,10 @@ import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
|
||||
import org.sleuthkit.datamodel.AbstractContent;
|
||||
import org.sleuthkit.datamodel.Account;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
|
||||
/**
|
||||
* A Panel that shows the media (thumbnails) for the selected account.
|
||||
@ -65,6 +69,7 @@ final class MediaViewer extends JPanel implements RelationshipsViewer, ExplorerM
|
||||
private final MessageDataContent contentViewer;
|
||||
|
||||
private MediaViewerWorker worker;
|
||||
private SelectionWorker selectionWorker;
|
||||
|
||||
@Messages({
|
||||
"MediaViewer_Name=Media Attachments"
|
||||
@ -106,12 +111,16 @@ final class MediaViewer extends JPanel implements RelationshipsViewer, ExplorerM
|
||||
@Override
|
||||
public void setSelectionInfo(SelectionInfo info) {
|
||||
contentViewer.setNode(null);
|
||||
thumbnailViewer.resetComponent();
|
||||
thumbnailViewer.setNode(null);
|
||||
|
||||
if (worker != null) {
|
||||
worker.cancel(true);
|
||||
}
|
||||
|
||||
if(selectionWorker != null) {
|
||||
selectionWorker.cancel(true);
|
||||
}
|
||||
|
||||
worker = new MediaViewerWorker(info);
|
||||
|
||||
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
@ -181,22 +190,67 @@ final class MediaViewer extends JPanel implements RelationshipsViewer, ExplorerM
|
||||
*/
|
||||
private void handleNodeSelectionChange() {
|
||||
final Node[] nodes = tableEM.getSelectedNodes();
|
||||
contentViewer.setNode(null);
|
||||
|
||||
if(selectionWorker != null) {
|
||||
selectionWorker.cancel(true);
|
||||
}
|
||||
|
||||
if (nodes != null && nodes.length == 1) {
|
||||
AbstractContent thumbnail = nodes[0].getLookup().lookup(AbstractContent.class);
|
||||
if (thumbnail != null) {
|
||||
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
selectionWorker = new SelectionWorker(thumbnail);
|
||||
selectionWorker.execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A SwingWorker to get the artifact associated with the selected thumbnail.
|
||||
*/
|
||||
private class SelectionWorker extends SwingWorker<BlackboardArtifact, Void> {
|
||||
|
||||
private final AbstractContent thumbnail;
|
||||
|
||||
// Construct a SelectionWorker.
|
||||
SelectionWorker(AbstractContent thumbnail) {
|
||||
this.thumbnail = thumbnail;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BlackboardArtifact doInBackground() throws Exception {
|
||||
SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase();
|
||||
List<BlackboardArtifact> artifactsList = skCase.getBlackboardArtifacts(TSK_ASSOCIATED_OBJECT, thumbnail.getId());
|
||||
for (BlackboardArtifact contextArtifact : artifactsList) {
|
||||
BlackboardAttribute associatedArtifactAttribute = contextArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
|
||||
if (associatedArtifactAttribute != null) {
|
||||
long artifactId = associatedArtifactAttribute.getValueLong();
|
||||
return contextArtifact.getSleuthkitCase().getBlackboardArtifact(artifactId);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
if (isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Content parentContent = thumbnail.getParent();
|
||||
if (parentContent != null && parentContent instanceof BlackboardArtifact) {
|
||||
contentViewer.setNode(new BlackboardArtifactNode((BlackboardArtifact) parentContent));
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "Unable to get parent Content from AbstraceContent instance.", ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
BlackboardArtifact artifact = get();
|
||||
if (artifact != null) {
|
||||
contentViewer.setNode(new BlackboardArtifactNode(artifact));
|
||||
} else {
|
||||
contentViewer.setNode(null);
|
||||
}
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
logger.log(Level.SEVERE, "Failed message viewer based on thumbnail selection. thumbnailID = " + thumbnail.getId(), ex);
|
||||
} finally {
|
||||
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2018-2019 Basis Technology Corp.
|
||||
* Copyright 2018-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -56,6 +56,7 @@ import org.openide.windows.WindowManager;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.guiutils.JFileChooserFactory;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
@ -76,6 +77,8 @@ class PListViewer extends javax.swing.JPanel implements FileTypeViewer, Explorer
|
||||
|
||||
private NSObject rootDict;
|
||||
|
||||
private final JFileChooserFactory fileChooserHelper = new JFileChooserFactory();
|
||||
|
||||
/**
|
||||
* Creates new form PListViewer
|
||||
*/
|
||||
@ -203,7 +206,7 @@ class PListViewer extends javax.swing.JPanel implements FileTypeViewer, Explorer
|
||||
return;
|
||||
}
|
||||
|
||||
final JFileChooser fileChooser = new JFileChooser();
|
||||
final JFileChooser fileChooser = fileChooserHelper.getChooser();
|
||||
fileChooser.setCurrentDirectory(new File(openCase.getExportDirectory()));
|
||||
fileChooser.setFileFilter(new FileNameExtensionFilter("XML file", "xml"));
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2018-2019 Basis Technology Corp.
|
||||
* Copyright 2018-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -49,6 +49,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.autopsy.coreutils.SQLiteTableReader;
|
||||
import org.sleuthkit.autopsy.guiutils.JFileChooserFactory;
|
||||
|
||||
/**
|
||||
* A file content viewer for SQLite database files.
|
||||
@ -75,6 +76,8 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
|
||||
SwingWorker<?, ?> worker;
|
||||
|
||||
private final JFileChooserFactory chooserHelper = new JFileChooserFactory();
|
||||
|
||||
/**
|
||||
* Constructs a file content viewer for SQLite database files.
|
||||
*/
|
||||
@ -280,7 +283,7 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
private void exportCsvButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exportCsvButtonActionPerformed
|
||||
Case openCase = Case.getCurrentCase();
|
||||
File caseDirectory = new File(openCase.getExportDirectory());
|
||||
JFileChooser fileChooser = new JFileChooser();
|
||||
JFileChooser fileChooser = chooserHelper.getChooser();
|
||||
fileChooser.setDragEnabled(false);
|
||||
fileChooser.setCurrentDirectory(caseDirectory);
|
||||
//Set a filter to let the filechooser only work for csv files
|
||||
|
@ -19,6 +19,7 @@
|
||||
package org.sleuthkit.autopsy.contentviewers.analysisresults;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.util.Objects;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.swing.SwingWorker;
|
||||
@ -28,30 +29,26 @@ import org.openide.util.lookup.ServiceProvider;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
|
||||
import org.sleuthkit.autopsy.datamodel.TskContentItem;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker;
|
||||
import org.sleuthkit.datamodel.AnalysisResult;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.autopsy.datamodel.AnalysisResultItem;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Displays a list of analysis results as a content viewer.
|
||||
* A content viewer that displays the analysis results for a Content object.
|
||||
*/
|
||||
@ServiceProvider(service = DataContentViewer.class, position = 7)
|
||||
public class AnalysisResultsContentViewer implements DataContentViewer {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(AnalysisResultsContentPanel.class.getName());
|
||||
|
||||
// isPreferred value
|
||||
private static final int PREFERRED_VALUE = 3;
|
||||
|
||||
private final AnalysisResultsViewModel viewModel = new AnalysisResultsViewModel();
|
||||
private final AnalysisResultsContentPanel panel = new AnalysisResultsContentPanel();
|
||||
|
||||
private SwingWorker<?, ?> worker = null;
|
||||
|
||||
|
||||
|
||||
@NbBundle.Messages({
|
||||
"AnalysisResultsContentViewer_title=Analysis Results"
|
||||
})
|
||||
@ -126,26 +123,24 @@ public class AnalysisResultsContentViewer implements DataContentViewer {
|
||||
|
||||
@Override
|
||||
public boolean isSupported(Node node) {
|
||||
if (node == null) {
|
||||
if (Objects.isNull(node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// There needs to either be a file with an AnalysisResult or an AnalysisResult in the lookup.
|
||||
for (Content content : node.getLookup().lookupAll(Content.class)) {
|
||||
if (content instanceof AnalysisResult) {
|
||||
AnalysisResultItem analysisResultItem = node.getLookup().lookup(AnalysisResultItem.class);
|
||||
if (Objects.nonNull(analysisResultItem)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (content == null || content instanceof BlackboardArtifact) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TskContentItem contentItem = node.getLookup().lookup(TskContentItem.class);
|
||||
if (!Objects.isNull(contentItem)) {
|
||||
Content content = contentItem.getTskContent();
|
||||
try {
|
||||
if (Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().hasAnalysisResults(content.getId())) {
|
||||
return true;
|
||||
}
|
||||
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Unable to get analysis results for file with obj id " + content.getId(), ex);
|
||||
logger.log(Level.SEVERE, String.format("Error getting analysis results for Content (object ID = %d)", content.getId()), ex);
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,4 +151,5 @@ public class AnalysisResultsContentViewer implements DataContentViewer {
|
||||
public int isPreferred(Node node) {
|
||||
return PREFERRED_VALUE;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,9 +20,8 @@ package org.sleuthkit.autopsy.contentviewers.analysisresults;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@ -31,14 +30,14 @@ import java.util.stream.Stream;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.datamodel.AnalysisResultItem;
|
||||
import org.sleuthkit.autopsy.datamodel.TskContentItem;
|
||||
import org.sleuthkit.datamodel.AnalysisResult;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.Score;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Creates a representation of a list of analysis results gathered from a node.
|
||||
*/
|
||||
public class AnalysisResultsViewModel {
|
||||
@ -72,7 +71,7 @@ public class AnalysisResultsViewModel {
|
||||
* @return The attributes to display.
|
||||
*/
|
||||
List<Pair<String, String>> getAttributesToDisplay() {
|
||||
return attributesToDisplay;
|
||||
return Collections.unmodifiableList(attributesToDisplay);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -118,7 +117,7 @@ public class AnalysisResultsViewModel {
|
||||
* @return The analysis results to be displayed.
|
||||
*/
|
||||
List<ResultDisplayAttributes> getAnalysisResults() {
|
||||
return analysisResults;
|
||||
return Collections.unmodifiableList(analysisResults);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -238,58 +237,44 @@ public class AnalysisResultsViewModel {
|
||||
return new NodeResults(Collections.emptyList(), Optional.empty(), Optional.empty(), Optional.empty());
|
||||
}
|
||||
|
||||
Optional<Score> aggregateScore = Optional.empty();
|
||||
Optional<Content> nodeContent = Optional.empty();
|
||||
// maps id of analysis result to analysis result to prevent duplication
|
||||
Map<Long, AnalysisResult> allAnalysisResults = new HashMap<>();
|
||||
Optional<AnalysisResult> selectedResult = Optional.empty();
|
||||
|
||||
// Find first content that is not an artifact within node
|
||||
for (Content content : node.getLookup().lookupAll(Content.class)) {
|
||||
if (content == null || content instanceof BlackboardArtifact) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Content analyzedContent = null;
|
||||
AnalysisResult selectedAnalysisResult = null;
|
||||
Score aggregateScore = null;
|
||||
List<AnalysisResult> analysisResults = Collections.emptyList();
|
||||
long selectedObjectId = 0;
|
||||
try {
|
||||
nodeContent = Optional.of(content);
|
||||
|
||||
// get the aggregate score of that content
|
||||
aggregateScore = Optional.ofNullable(content.getAggregateScore());
|
||||
|
||||
// and add all analysis results to mapping
|
||||
content.getAllAnalysisResults().stream()
|
||||
.forEach((ar) -> allAnalysisResults.put(ar.getArtifactID(), ar));
|
||||
|
||||
break;
|
||||
AnalysisResultItem analysisResultItem = node.getLookup().lookup(AnalysisResultItem.class);
|
||||
if (Objects.nonNull(analysisResultItem)) {
|
||||
/*
|
||||
* The content represented by the Node is an analysis result.
|
||||
* Set this analysis result as the analysis result to be
|
||||
* selected in the content viewer and get the analyzed content
|
||||
* as the source of the analysis results to display.
|
||||
*/
|
||||
selectedAnalysisResult = analysisResultItem.getAnalysisResult();
|
||||
selectedObjectId = selectedAnalysisResult.getId();
|
||||
analyzedContent = selectedAnalysisResult.getParent();
|
||||
} else {
|
||||
/*
|
||||
* The content represented by the Node is something other than
|
||||
* an analysis result. Use it as the source of the analysis
|
||||
* results to display.
|
||||
*/
|
||||
TskContentItem contentItem = node.getLookup().lookup(TskContentItem.class);
|
||||
analyzedContent = contentItem.getTskContent();
|
||||
selectedObjectId = analyzedContent.getId();
|
||||
}
|
||||
aggregateScore = analyzedContent.getAggregateScore();
|
||||
analysisResults = analyzedContent.getAllAnalysisResults();
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Unable to get analysis results for content with obj id " + content.getId(), ex);
|
||||
}
|
||||
logger.log(Level.SEVERE, String.format("Error getting analysis result data for selected Content (object ID=%d)", selectedObjectId), ex);
|
||||
}
|
||||
|
||||
// Find any analysis results in the node
|
||||
Collection<? extends AnalysisResult> analysisResults = node.getLookup().lookupAll(AnalysisResult.class);
|
||||
if (analysisResults.size() > 0) {
|
||||
|
||||
// get any items with a score
|
||||
List<AnalysisResult> filteredResults = analysisResults.stream()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// add them to the map to display
|
||||
filteredResults.forEach((ar) -> allAnalysisResults.put(ar.getArtifactID(), ar));
|
||||
|
||||
// the selected result will be the highest scored analysis result in the node.
|
||||
selectedResult = filteredResults.stream()
|
||||
.max((a, b) -> a.getScore().compareTo(b.getScore()));
|
||||
|
||||
// if no aggregate score determined at this point, use the selected result score.
|
||||
if (!aggregateScore.isPresent()) {
|
||||
aggregateScore = selectedResult.flatMap(selectedRes -> Optional.ofNullable(selectedRes.getScore()));
|
||||
}
|
||||
/*
|
||||
* Use the data collected above to construct the view model.
|
||||
*/
|
||||
List<ResultDisplayAttributes> displayAttributes = getOrderedDisplayAttributes(analysisResults);
|
||||
return new NodeResults(displayAttributes, Optional.ofNullable(selectedAnalysisResult), Optional.ofNullable(aggregateScore), Optional.ofNullable(analyzedContent));
|
||||
}
|
||||
|
||||
// get view model representation
|
||||
List<ResultDisplayAttributes> displayAttributes = getOrderedDisplayAttributes(allAnalysisResults.values());
|
||||
|
||||
return new NodeResults(displayAttributes, selectedResult, aggregateScore, nodeContent);
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +55,7 @@ import org.sleuthkit.autopsy.machinesettings.UserMachinePreferencesException;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
||||
import org.sleuthkit.autopsy.coreutils.Version;
|
||||
import org.sleuthkit.autopsy.guiutils.JFileChooserFactory;
|
||||
import org.sleuthkit.autopsy.machinesettings.UserMachinePreferences.TempDirChoice;
|
||||
import org.sleuthkit.autopsy.report.ReportBranding;
|
||||
|
||||
@ -82,8 +83,8 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String DEFAULT_HEAP_DUMP_FILE_FIELD = "";
|
||||
private final JFileChooser logoFileChooser;
|
||||
private final JFileChooser tempDirChooser;
|
||||
private JFileChooser logoFileChooser;
|
||||
private JFileChooser tempDirChooser;
|
||||
private static final String ETC_FOLDER_NAME = "etc";
|
||||
private static final String CONFIG_FILE_EXTENSION = ".conf";
|
||||
private static final long ONE_BILLION = 1000000000L; //used to roughly convert system memory from bytes to gigabytes
|
||||
@ -94,27 +95,17 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||
private String initialMemValue = Long.toString(Runtime.getRuntime().maxMemory() / ONE_BILLION);
|
||||
|
||||
private final ReportBranding reportBranding;
|
||||
private final JFileChooser heapFileChooser;
|
||||
private JFileChooser heapFileChooser;
|
||||
|
||||
private final JFileChooserFactory logoChooserHelper = new JFileChooserFactory();
|
||||
private final JFileChooserFactory heapChooserHelper = new JFileChooserFactory();
|
||||
private final JFileChooserFactory tempChooserHelper = new JFileChooserFactory();
|
||||
|
||||
/**
|
||||
* Instantiate the Autopsy options panel.
|
||||
*/
|
||||
AutopsyOptionsPanel() {
|
||||
initComponents();
|
||||
logoFileChooser = new JFileChooser();
|
||||
logoFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||
logoFileChooser.setMultiSelectionEnabled(false);
|
||||
logoFileChooser.setAcceptAllFileFilterUsed(false);
|
||||
logoFileChooser.setFileFilter(new GeneralFilter(GeneralFilter.GRAPHIC_IMAGE_EXTS, GeneralFilter.GRAPHIC_IMG_DECR));
|
||||
|
||||
tempDirChooser = new JFileChooser();
|
||||
tempDirChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
||||
tempDirChooser.setMultiSelectionEnabled(false);
|
||||
|
||||
heapFileChooser = new JFileChooser();
|
||||
heapFileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
||||
heapFileChooser.setMultiSelectionEnabled(false);
|
||||
|
||||
if (!isJVMHeapSettingsCapable()) {
|
||||
//32 bit JVM has a max heap size of 1.4 gb to 4 gb depending on OS
|
||||
//So disabling the setting of heap size when the JVM is not 64 bit
|
||||
@ -1242,6 +1233,11 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||
"# {0} - path",
|
||||
"AutopsyOptionsPanel_tempDirectoryBrowseButtonActionPerformed_onInvalidPath_description=Unable to create temporary directory within specified path: {0}",})
|
||||
private void tempDirectoryBrowseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tempDirectoryBrowseButtonActionPerformed
|
||||
if(tempDirChooser == null) {
|
||||
tempDirChooser = tempChooserHelper.getChooser();
|
||||
tempDirChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
||||
tempDirChooser.setMultiSelectionEnabled(false);
|
||||
}
|
||||
int returnState = tempDirChooser.showOpenDialog(this);
|
||||
if (returnState == JFileChooser.APPROVE_OPTION) {
|
||||
String specifiedPath = tempDirChooser.getSelectedFile().getPath();
|
||||
@ -1318,6 +1314,13 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||
}//GEN-LAST:event_defaultLogoRBActionPerformed
|
||||
|
||||
private void browseLogosButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseLogosButtonActionPerformed
|
||||
if(logoFileChooser == null) {
|
||||
logoFileChooser = logoChooserHelper.getChooser();
|
||||
logoFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||
logoFileChooser.setMultiSelectionEnabled(false);
|
||||
logoFileChooser.setAcceptAllFileFilterUsed(false);
|
||||
logoFileChooser.setFileFilter(new GeneralFilter(GeneralFilter.GRAPHIC_IMAGE_EXTS, GeneralFilter.GRAPHIC_IMG_DECR));
|
||||
}
|
||||
String oldLogoPath = agencyLogoPathField.getText();
|
||||
int returnState = logoFileChooser.showOpenDialog(this);
|
||||
if (returnState == JFileChooser.APPROVE_OPTION) {
|
||||
@ -1360,6 +1363,11 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||
"AutopsyOptionsPanel_heapDumpBrowseButtonActionPerformed_fileAlreadyExistsMessage=File already exists. Please select a new location."
|
||||
})
|
||||
private void heapDumpBrowseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_heapDumpBrowseButtonActionPerformed
|
||||
if(heapFileChooser == null) {
|
||||
heapFileChooser = heapChooserHelper.getChooser();
|
||||
heapFileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
||||
heapFileChooser.setMultiSelectionEnabled(false);
|
||||
}
|
||||
String oldHeapPath = heapDumpFileField.getText();
|
||||
if (!StringUtils.isBlank(oldHeapPath)) {
|
||||
heapFileChooser.setCurrentDirectory(new File(oldHeapPath));
|
||||
|
@ -102,7 +102,7 @@ public abstract class AbstractContentNode<T extends Content> extends ContentNode
|
||||
* @param content Underlying Content instances
|
||||
*/
|
||||
AbstractContentNode(T content) {
|
||||
this(content, Lookups.singleton(content));
|
||||
this(content, Lookups.fixed(content, new TskContentItem(content)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
51
Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResultItem.java
Executable file
51
Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResultItem.java
Executable file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2021-2021 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.datamodel;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import org.sleuthkit.datamodel.AnalysisResult;
|
||||
|
||||
/**
|
||||
* An Autopsy Data Model item with an underlying analysis result Sleuth Kit Data
|
||||
* Model object.
|
||||
*/
|
||||
public class AnalysisResultItem extends TskContentItem {
|
||||
|
||||
/**
|
||||
* Constructs an Autopsy Data Model item with an underlying AnalysisResult
|
||||
* Sleuth Kit Data Model object.
|
||||
*
|
||||
* @param analysisResult The analysis result.
|
||||
*/
|
||||
@Beta
|
||||
AnalysisResultItem(AnalysisResult analysisResult) {
|
||||
super(analysisResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the underlying analysis result.
|
||||
*
|
||||
* @return The analysis result.
|
||||
*/
|
||||
@Beta
|
||||
public AnalysisResult getAnalysisResult() {
|
||||
return (AnalysisResult) (getTskContent());
|
||||
}
|
||||
|
||||
}
|
@ -84,8 +84,8 @@ import org.sleuthkit.datamodel.BlackboardArtifact.Category;
|
||||
import org.sleuthkit.datamodel.Score;
|
||||
|
||||
/**
|
||||
* A BlackboardArtifactNode is an AbstractNode implementation that can be used
|
||||
* to represent an artifact of any type.
|
||||
* An AbstractNode implementation that can be used to represent an data artifact
|
||||
* or analysis result of any type.
|
||||
*/
|
||||
public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifact> {
|
||||
|
||||
@ -219,11 +219,14 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
private final PropertyChangeListener weakListener = WeakListeners.propertyChange(listener, null);
|
||||
|
||||
/**
|
||||
* Constructs a BlackboardArtifactNode, an AbstractNode implementation that
|
||||
* can be used to represent an artifact of any type.
|
||||
* Constructs an AbstractNode implementation that can be used to represent a
|
||||
* data artifact or analysis result of any type. The Lookup of the Node will
|
||||
* contain the data artifact or analysis result and its parent content as
|
||||
* its source content.
|
||||
*
|
||||
* @param artifact The artifact to represent.
|
||||
* @param iconPath The path to the icon for the artifact type.
|
||||
* @param artifact The data artifact or analysis result.
|
||||
* @param iconPath The path to the icon for the data artifact or analysis
|
||||
* result type.
|
||||
*/
|
||||
public BlackboardArtifactNode(BlackboardArtifact artifact, String iconPath) {
|
||||
super(artifact, createLookup(artifact, false));
|
||||
@ -256,26 +259,28 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a BlackboardArtifactNode, an AbstractNode implementation that
|
||||
* can be used to represent an artifact of any type.
|
||||
* Constructs an AbstractNode implementation that can be used to represent a
|
||||
* data artifact or analysis result of any type. The Lookup of the Node will
|
||||
* contain the data artifact or analysis result and its source content,
|
||||
* either the parent content or the associated file.
|
||||
*
|
||||
* @param artifact The artifact to represent.
|
||||
* @param lookupIsAssociatedFile True if the Content lookup should be made
|
||||
* for the associated file instead of the
|
||||
* parent file.
|
||||
* @param artifact The data artifact or analysis result.
|
||||
* @param useAssociatedFileInLookup True if the source content in the Lookup
|
||||
* should be the associated file instead of
|
||||
* the parent content.
|
||||
*/
|
||||
@Beta
|
||||
public BlackboardArtifactNode(BlackboardArtifact artifact, boolean lookupIsAssociatedFile) {
|
||||
super(artifact, createLookup(artifact, lookupIsAssociatedFile));
|
||||
public BlackboardArtifactNode(BlackboardArtifact artifact, boolean useAssociatedFileInLookup) {
|
||||
super(artifact, createLookup(artifact, useAssociatedFileInLookup));
|
||||
this.artifact = artifact;
|
||||
this.artifactType = getType(artifact);
|
||||
|
||||
try {
|
||||
//The lookup for a file may or may not exist so we define the srcContent as the parent.
|
||||
srcContent = artifact.getParent();
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, MessageFormat.format("Error getting the parent of the artifact for (artifact objID={0})", artifact.getId()), ex);
|
||||
}
|
||||
|
||||
if (srcContent != null) {
|
||||
try {
|
||||
/*
|
||||
@ -291,6 +296,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
} else {
|
||||
throw new IllegalArgumentException(MessageFormat.format("Artifact missing source content (artifact objID={0})", artifact));
|
||||
}
|
||||
|
||||
setName(Long.toString(artifact.getArtifactID()));
|
||||
String displayName = srcContent.getName();
|
||||
setDisplayName(displayName);
|
||||
@ -301,10 +307,12 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a BlackboardArtifactNode, an AbstractNode implementation that
|
||||
* can be used to represent an artifact of any type.
|
||||
* Constructs an AbstractNode implementation that can be used to represent a
|
||||
* data artifact or analysis result of any type. The Lookup of the Node will
|
||||
* contain the data artifact or analysis result and its parent content as
|
||||
* its source content.
|
||||
*
|
||||
* @param artifact The artifact to represent.
|
||||
* @param artifact The data artifact or analysis result.
|
||||
*/
|
||||
public BlackboardArtifactNode(BlackboardArtifact artifact) {
|
||||
this(artifact, IconsUtil.getIconFilePath(artifact.getArtifactTypeID()));
|
||||
@ -312,7 +320,9 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
|
||||
/**
|
||||
* Returns the artifact type of the artifact.
|
||||
*
|
||||
* @param artifact The artifact.
|
||||
*
|
||||
* @return The artifact type or null if no type could be retrieved.
|
||||
*/
|
||||
private static BlackboardArtifact.Type getType(BlackboardArtifact artifact) {
|
||||
@ -329,53 +339,51 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
* artifact this node represents and its source content.
|
||||
*
|
||||
* @param artifact The artifact this node represents.
|
||||
* @param useAssociatedFile True if the source content in the Lookup should
|
||||
* be the associated file instead of the parent
|
||||
* content.
|
||||
*
|
||||
* @return The Lookup.
|
||||
*/
|
||||
private static Lookup createLookup(BlackboardArtifact artifact) {
|
||||
final long objectID = artifact.getObjectID();
|
||||
try {
|
||||
Content content = contentCache.get(objectID, () -> artifact.getSleuthkitCase().getContentById(objectID));
|
||||
if (content == null) {
|
||||
return Lookups.fixed(artifact);
|
||||
} else {
|
||||
return Lookups.fixed(artifact, content);
|
||||
}
|
||||
} catch (ExecutionException ex) {
|
||||
logger.log(Level.SEVERE, MessageFormat.format("Error getting source content (artifact objID={0}", artifact.getId()), ex); //NON-NLS
|
||||
return Lookups.fixed(artifact);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Lookup object for this node and populates it with both the
|
||||
* artifact this node represents and its source content.
|
||||
*
|
||||
* @param artifact The artifact this node represents.
|
||||
* @param lookupIsAssociatedFile True if the Content lookup should be made
|
||||
* for the associated file instead of the
|
||||
* parent file.
|
||||
*
|
||||
* @return The Lookup.
|
||||
private static Lookup createLookup(BlackboardArtifact artifact, boolean useAssociatedFile) {
|
||||
/*
|
||||
* Get the source content.
|
||||
*/
|
||||
private static Lookup createLookup(BlackboardArtifact artifact, boolean lookupIsAssociatedFile) {
|
||||
Content content = null;
|
||||
if (lookupIsAssociatedFile) {
|
||||
try {
|
||||
if (useAssociatedFile) {
|
||||
content = getPathIdFile(artifact);
|
||||
} else {
|
||||
long srcObjectID = artifact.getObjectID();
|
||||
content = contentCache.get(srcObjectID, () -> artifact.getSleuthkitCase().getContentById(srcObjectID));
|
||||
}
|
||||
} catch (ExecutionException ex) {
|
||||
logger.log(Level.SEVERE, MessageFormat.format("Error getting source content (artifact objID={0}", artifact.getId()), ex); //NON-NLS
|
||||
content = null;
|
||||
}
|
||||
if (content == null) {
|
||||
return Lookups.fixed(artifact);
|
||||
} else {
|
||||
return Lookups.fixed(artifact, content);
|
||||
}
|
||||
} else {
|
||||
return createLookup(artifact);
|
||||
logger.log(Level.SEVERE, MessageFormat.format("Error getting source/associated content (artifact object ID={0})", artifact.getId()), ex); //NON-NLS
|
||||
}
|
||||
|
||||
/*
|
||||
* Make an Autopsy Data Model wrapper for the artifact.
|
||||
*
|
||||
* NOTE: The creation of an Autopsy Data Model independent of the
|
||||
* NetBeans nodes is a work in progress. At the time this comment is
|
||||
* being written, this object is only used by the analysis content
|
||||
* viewer.
|
||||
*/
|
||||
TskContentItem artifactItem;
|
||||
if (artifact instanceof AnalysisResult) {
|
||||
artifactItem = new AnalysisResultItem((AnalysisResult) artifact);
|
||||
} else {
|
||||
artifactItem = new TskContentItem(artifact);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the Lookup.
|
||||
*/
|
||||
if (content == null) {
|
||||
return Lookups.fixed(artifact, artifactItem);
|
||||
} else {
|
||||
return Lookups.fixed(artifact, artifactItem, content);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -470,8 +478,8 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
* action to view it in the timeline.
|
||||
*/
|
||||
try {
|
||||
if (ViewArtifactInTimelineAction.hasSupportedTimeStamp(artifact) &&
|
||||
// don't show ViewArtifactInTimelineAction for AnalysisResults.
|
||||
if (ViewArtifactInTimelineAction.hasSupportedTimeStamp(artifact)
|
||||
&& // don't show ViewArtifactInTimelineAction for AnalysisResults.
|
||||
(!(this.artifact instanceof AnalysisResult))) {
|
||||
|
||||
actionsList.add(new ViewArtifactInTimelineAction(artifact));
|
||||
|
@ -99,6 +99,7 @@ public abstract class DisplayableItemNode extends AbstractNode {
|
||||
* operation on this artifact type and return some object as the result of
|
||||
* the operation.
|
||||
*
|
||||
* @param <T> The return type.
|
||||
* @param visitor The visitor, where the type parameter of the visitor is
|
||||
* the type of the object that will be returned as the result
|
||||
* of the visit operation.
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2012-2019 Basis Technology Corp.
|
||||
* Copyright 2012-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -110,7 +110,7 @@ public class ImageNode extends AbstractContentNode<Image> {
|
||||
actionsList.add(a);
|
||||
}
|
||||
actionsList.addAll(ExplorerNodeActionVisitor.getActions(content));
|
||||
actionsList.add(new FileSearchAction(Bundle.ImageNode_getActions_openFileSearchByAttr_text()));
|
||||
actionsList.add(new FileSearchAction(Bundle.ImageNode_getActions_openFileSearchByAttr_text(), content.getId()));
|
||||
actionsList.add(new ViewSummaryInformationAction(content.getId()));
|
||||
actionsList.add(new RunIngestModulesAction(Collections.<Content>singletonList(content)));
|
||||
actionsList.add(new NewWindowViewAction(NbBundle.getMessage(this.getClass(), "ImageNode.getActions.viewInNewWin.text"), this));
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2017-2019 Basis Technology Corp.
|
||||
* Copyright 2017-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -65,7 +65,7 @@ public abstract class SpecialDirectoryNode extends AbstractAbstractFileNode<Spec
|
||||
actions.add(ExtractAction.getInstance());
|
||||
actions.add(ExportCSVAction.getInstance());
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(new FileSearchAction(Bundle.ImageNode_getActions_openFileSearchByAttr_text()));
|
||||
actions.add(new FileSearchAction(Bundle.ImageNode_getActions_openFileSearchByAttr_text(), content.getId()));
|
||||
if (content.isDataSource()) {
|
||||
actions.add(new ViewSummaryInformationAction(content.getId()));
|
||||
actions.add(new RunIngestModulesAction(Collections.<Content>singletonList(content)));
|
||||
|
56
Core/src/org/sleuthkit/autopsy/datamodel/TskContentItem.java
Executable file
56
Core/src/org/sleuthkit/autopsy/datamodel/TskContentItem.java
Executable file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2021-2021 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.datamodel;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
|
||||
/**
|
||||
* An Autopsy Data Model item with an underlying Sleuth Kit Data Model object
|
||||
* that implements the Sleuth Kit Data Model's Content interface.
|
||||
*/
|
||||
@Beta
|
||||
public class TskContentItem {
|
||||
|
||||
private final Content tskContent;
|
||||
|
||||
/**
|
||||
* Constructs an Autopsy Data Model item with an underlying Sleuth Kit Data
|
||||
* Model object that implements the Sleuth Kit Data Model's Content
|
||||
* interface.
|
||||
*
|
||||
* @param content The underlying Sleuth Kit Data Model object.
|
||||
*
|
||||
*/
|
||||
@Beta
|
||||
TskContentItem(Content sleuthKitContent) {
|
||||
this.tskContent = sleuthKitContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the underlying Sleuth Kit Data Model object.
|
||||
*
|
||||
* @return The Sleuth Kit Data Model object.
|
||||
*/
|
||||
@Beta
|
||||
public Content getTskContent() {
|
||||
return tskContent;
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2018 Basis Technology Corp.
|
||||
* Copyright 2011-2021 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.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
||||
import org.sleuthkit.autopsy.coreutils.PathValidator;
|
||||
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
|
||||
import org.sleuthkit.autopsy.guiutils.JFileChooserFactory;
|
||||
|
||||
/**
|
||||
* Allows examiner to supply a raw data source.
|
||||
@ -41,7 +42,8 @@ final class RawDSInputPanel extends JPanel implements DocumentListener {
|
||||
private static final long TWO_GB = 2000000000L;
|
||||
private static final long serialVersionUID = 1L; //default
|
||||
private final String PROP_LASTINPUT_PATH = "LBL_LastInputFile_PATH";
|
||||
private final JFileChooser fc = new JFileChooser();
|
||||
private JFileChooser fc;
|
||||
private JFileChooserFactory chooserHelper = new JFileChooserFactory();
|
||||
// Externally supplied name is used to store settings
|
||||
private final String contextName;
|
||||
/**
|
||||
@ -51,11 +53,6 @@ final class RawDSInputPanel extends JPanel implements DocumentListener {
|
||||
initComponents();
|
||||
|
||||
errorLabel.setVisible(false);
|
||||
|
||||
fc.setDragEnabled(false);
|
||||
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||
fc.setMultiSelectionEnabled(false);
|
||||
|
||||
this.contextName = context;
|
||||
}
|
||||
|
||||
@ -200,6 +197,13 @@ final class RawDSInputPanel extends JPanel implements DocumentListener {
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
@SuppressWarnings("deprecation")
|
||||
private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed
|
||||
if (fc == null) {
|
||||
fc = chooserHelper.getChooser();
|
||||
fc.setDragEnabled(false);
|
||||
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||
fc.setMultiSelectionEnabled(false);
|
||||
}
|
||||
|
||||
String oldText = pathTextField.getText();
|
||||
// set the current directory of the FileChooser if the ImagePath Field is valid
|
||||
File currentDir = new File(oldText);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2019 Basis Technology Corp.
|
||||
* Copyright 2019-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -30,6 +30,7 @@ import javax.swing.JPanel;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
||||
import org.sleuthkit.autopsy.guiutils.JFileChooserFactory;
|
||||
|
||||
/**
|
||||
* Allows an examiner to configure the XRY Data source processor.
|
||||
@ -49,6 +50,8 @@ final class XRYDataSourceProcessorConfigPanel extends JPanel {
|
||||
//panel will indicate when it is ready for an update.
|
||||
private final PropertyChangeSupport pcs;
|
||||
|
||||
private final JFileChooserFactory chooserHelper = new JFileChooserFactory();
|
||||
|
||||
/**
|
||||
* Creates new form XRYDataSourceConfigPanel.
|
||||
* Prevent direct instantiation.
|
||||
@ -191,7 +194,7 @@ final class XRYDataSourceProcessorConfigPanel extends JPanel {
|
||||
* report folder.
|
||||
*/
|
||||
private void fileBrowserButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fileBrowserButtonActionPerformed
|
||||
JFileChooser fileChooser = new JFileChooser();
|
||||
JFileChooser fileChooser = chooserHelper.getChooser();
|
||||
fileChooser.setMultiSelectionEnabled(false);
|
||||
fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
||||
Optional<Path> lastUsedPath = getLastUsedPath();
|
||||
|
22
Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java
Normal file → Executable file
22
Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java
Normal file → Executable file
@ -18,9 +18,7 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datasourcesummary.datamodel;
|
||||
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@ -31,30 +29,23 @@ import java.util.stream.Collectors;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Providing data for the data source analysis tab.
|
||||
* Helper class for getting hash set hits, keyword hits, and interesting item
|
||||
* hits within a datasource.
|
||||
*/
|
||||
public class AnalysisSummary implements DefaultArtifactUpdateGovernor {
|
||||
public class AnalysisSummary {
|
||||
|
||||
private static final BlackboardAttribute.Type TYPE_SET_NAME = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SET_NAME);
|
||||
|
||||
private static final Set<String> EXCLUDED_KEYWORD_SEARCH_ITEMS = new HashSet<>();
|
||||
|
||||
private static final Set<Integer> ARTIFACT_UPDATE_TYPE_IDS = new HashSet<>(Arrays.asList(
|
||||
ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(),
|
||||
ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID(),
|
||||
ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID(),
|
||||
ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()
|
||||
));
|
||||
|
||||
private final SleuthkitCaseProvider provider;
|
||||
|
||||
/**
|
||||
@ -73,11 +64,6 @@ public class AnalysisSummary implements DefaultArtifactUpdateGovernor {
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Integer> getArtifactTypeIdsForRefresh() {
|
||||
return ARTIFACT_UPDATE_TYPE_IDS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets counts for hashset hits.
|
||||
*
|
||||
|
0
Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/Bundle.properties-MERGED
Normal file → Executable file
0
Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/Bundle.properties-MERGED
Normal file → Executable file
0
Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/Bundle_ja.properties
Normal file → Executable file
0
Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/Bundle_ja.properties
Normal file → Executable file
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020 Basis Technology Corp.
|
||||
* Copyright 2020-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020 Basis Technology Corp.
|
||||
* Copyright 2020-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -64,6 +64,7 @@ class ClosestCityMapper {
|
||||
* Retrieves singleton instance of this class.
|
||||
*
|
||||
* @return The singleton instance of this class.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
static ClosestCityMapper getInstance() throws IOException {
|
||||
@ -97,6 +98,7 @@ class ClosestCityMapper {
|
||||
* @param citiesInputStream The input stream for the csv text file
|
||||
* containing the cities.
|
||||
* @param logger The logger to be used with this.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private ClosestCityMapper(InputStream citiesInputStream, java.util.logging.Logger logger) throws IOException {
|
||||
@ -109,6 +111,7 @@ class ClosestCityMapper {
|
||||
* city can be determined.
|
||||
*
|
||||
* @param point The point to locate.
|
||||
*
|
||||
* @return The closest city or null if no close city can be found.
|
||||
*/
|
||||
CityRecord findClosest(CityRecord point) {
|
||||
@ -120,6 +123,7 @@ class ClosestCityMapper {
|
||||
* returned.
|
||||
*
|
||||
* @param s The string to parse.
|
||||
*
|
||||
* @return The double value or null if value cannot be parsed.
|
||||
*/
|
||||
private Double tryParse(String s) {
|
||||
@ -140,6 +144,7 @@ class ClosestCityMapper {
|
||||
*
|
||||
* @param orig The original string value.
|
||||
* @param lineNum The line number that this country was found.
|
||||
*
|
||||
* @return The country name.
|
||||
*/
|
||||
private String parseCountryName(String orig, int lineNum) {
|
||||
@ -162,6 +167,7 @@ class ClosestCityMapper {
|
||||
* @param csvRow The row of data where each item in the list is each column
|
||||
* in the row.
|
||||
* @param lineNum The line number for this csv row.
|
||||
*
|
||||
* @return The parsed CityRecord or null if none can be determined.
|
||||
*/
|
||||
private CityRecord getCsvCityRecord(List<String> csvRow, int lineNum) {
|
||||
@ -201,6 +207,7 @@ class ClosestCityMapper {
|
||||
*
|
||||
* @param line The line to parse.
|
||||
* @param lineNum The line number in the csv where this line is.
|
||||
*
|
||||
* @return The list of column values.
|
||||
*/
|
||||
private List<String> parseCsvLine(String line, int lineNum) {
|
||||
@ -225,7 +232,9 @@ class ClosestCityMapper {
|
||||
* @param csvInputStream The csv file input stream.
|
||||
* @param ignoreHeaderRow Whether or not there is a header row in the csv
|
||||
* file.
|
||||
*
|
||||
* @return The list of city records.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private List<CityRecord> parseCsvLines(InputStream csvInputStream, boolean ignoreHeaderRow) throws IOException {
|
||||
|
257
Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummary.java
Normal file → Executable file
257
Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummary.java
Normal file → Executable file
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020 Basis Technology Corp.
|
||||
* Copyright 2020-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -18,29 +18,25 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datasourcesummary.datamodel;
|
||||
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
|
||||
import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import org.sleuthkit.datamodel.Image;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
/**
|
||||
* Provides methods to query for data source overview details.
|
||||
*/
|
||||
public class ContainerSummary implements DefaultArtifactUpdateGovernor {
|
||||
|
||||
private static final Set<Integer> ARTIFACT_UPDATE_TYPE_IDS = new HashSet<>(Arrays.asList(
|
||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_OS_INFO.getTypeID(),
|
||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_DATA_SOURCE_USAGE.getTypeID()
|
||||
));
|
||||
public class ContainerSummary {
|
||||
|
||||
private final SleuthkitCaseProvider provider;
|
||||
|
||||
@ -60,21 +56,6 @@ public class ContainerSummary implements DefaultArtifactUpdateGovernor {
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshRequired(ModuleContentEvent evt) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshRequired(AbstractFile file) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Integer> getArtifactTypeIdsForRefresh() {
|
||||
return ARTIFACT_UPDATE_TYPE_IDS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size of unallocated files in a particular datasource.
|
||||
*
|
||||
@ -231,4 +212,228 @@ public class ContainerSummary implements DefaultArtifactUpdateGovernor {
|
||||
String separator = ", ";
|
||||
return getConcattedStringsResult(query, valueParam, separator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data model data for data source images.
|
||||
*/
|
||||
public static class ImageDetails {
|
||||
|
||||
private final long unallocatedSize;
|
||||
private final long size;
|
||||
private final long sectorSize;
|
||||
|
||||
private final String timeZone;
|
||||
private final String imageType;
|
||||
|
||||
private final List<String> paths;
|
||||
private final String md5Hash;
|
||||
private final String sha1Hash;
|
||||
private final String sha256Hash;
|
||||
|
||||
/**
|
||||
* Main constructor.
|
||||
*
|
||||
* @param unallocatedSize Size in bytes of unallocated space.
|
||||
* @param size Total size in bytes.
|
||||
* @param sectorSize Sector size in bytes.
|
||||
* @param timeZone The time zone.
|
||||
* @param imageType The type of image.
|
||||
* @param paths The source paths for the image.
|
||||
* @param md5Hash The md5 hash or null.
|
||||
* @param sha1Hash The sha1 hash or null.
|
||||
* @param sha256Hash The sha256 hash or null.
|
||||
*/
|
||||
ImageDetails(long unallocatedSize, long size, long sectorSize,
|
||||
String timeZone, String imageType, List<String> paths, String md5Hash,
|
||||
String sha1Hash, String sha256Hash) {
|
||||
this.unallocatedSize = unallocatedSize;
|
||||
this.size = size;
|
||||
this.sectorSize = sectorSize;
|
||||
this.timeZone = timeZone;
|
||||
this.imageType = imageType;
|
||||
this.paths = paths == null ? Collections.emptyList() : new ArrayList<>(paths);
|
||||
this.md5Hash = md5Hash;
|
||||
this.sha1Hash = sha1Hash;
|
||||
this.sha256Hash = sha256Hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Size in bytes of unallocated space.
|
||||
*/
|
||||
public long getUnallocatedSize() {
|
||||
return unallocatedSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Total size in bytes.
|
||||
*/
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Sector size in bytes.
|
||||
*/
|
||||
public long getSectorSize() {
|
||||
return sectorSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The time zone.
|
||||
*/
|
||||
public String getTimeZone() {
|
||||
return timeZone;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The type of image.
|
||||
*/
|
||||
public String getImageType() {
|
||||
return imageType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The source paths for the image.
|
||||
*/
|
||||
public List<String> getPaths() {
|
||||
return Collections.unmodifiableList(paths);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The md5 hash or null.
|
||||
*/
|
||||
public String getMd5Hash() {
|
||||
return md5Hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The sha1 hash or null.
|
||||
*/
|
||||
public String getSha1Hash() {
|
||||
return sha1Hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The sha256 hash or null.
|
||||
*/
|
||||
public String getSha256Hash() {
|
||||
return sha256Hash;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Data model for container data.
|
||||
*/
|
||||
public static class ContainerDetails {
|
||||
|
||||
private final String displayName;
|
||||
private final String originalName;
|
||||
private final String deviceIdValue;
|
||||
private final String acquisitionDetails;
|
||||
private final ImageDetails imageDetails;
|
||||
|
||||
/**
|
||||
* Main constructor.
|
||||
*
|
||||
* @param displayName The display name for this data source.
|
||||
* @param originalName The original name for this data source.
|
||||
* @param deviceIdValue The device id value for this data source.
|
||||
* @param acquisitionDetails The acquisition details for this data
|
||||
* source or null.
|
||||
* @param imageDetails If the data source is an image, the image
|
||||
* data model for this data source or null if
|
||||
* non-image.
|
||||
*/
|
||||
ContainerDetails(String displayName, String originalName, String deviceIdValue,
|
||||
String acquisitionDetails, ImageDetails imageDetails) {
|
||||
this.displayName = displayName;
|
||||
this.originalName = originalName;
|
||||
this.deviceIdValue = deviceIdValue;
|
||||
this.acquisitionDetails = acquisitionDetails;
|
||||
this.imageDetails = imageDetails;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The display name for this data source.
|
||||
*/
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The original name for this data source.
|
||||
*/
|
||||
public String getOriginalName() {
|
||||
return originalName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The device id value for this data source.
|
||||
*/
|
||||
public String getDeviceId() {
|
||||
return deviceIdValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The acquisition details for this data source or null.
|
||||
*/
|
||||
public String getAcquisitionDetails() {
|
||||
return acquisitionDetails;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return If the data source is an image, the image details for this
|
||||
* data source or null if non-image.
|
||||
*/
|
||||
public ImageDetails getImageDetails() {
|
||||
return imageDetails;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a container data model object containing data about the data
|
||||
* source.
|
||||
*
|
||||
* @param ds The data source.
|
||||
*
|
||||
* @return The generated view model.
|
||||
*/
|
||||
public ContainerDetails getContainerDetails(DataSource ds) throws TskCoreException, SQLException, SleuthkitCaseProvider.SleuthkitCaseProviderException {
|
||||
if (ds == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ContainerDetails(
|
||||
ds.getName(),
|
||||
ds.getName(),
|
||||
ds.getDeviceId(),
|
||||
ds.getAcquisitionDetails(),
|
||||
ds instanceof Image ? getImageDetails((Image) ds) : null
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an image data model object containing data about the image.
|
||||
*
|
||||
* @param image The image.
|
||||
*
|
||||
* @return The generated view model.
|
||||
*/
|
||||
public ImageDetails getImageDetails(Image image) throws TskCoreException, SQLException, SleuthkitCaseProvider.SleuthkitCaseProviderException {
|
||||
if (image == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Long unallocSize = getSizeOfUnallocatedFiles(image);
|
||||
String imageType = image.getType().getName();
|
||||
Long size = image.getSize();
|
||||
Long sectorSize = image.getSsize();
|
||||
String timeZone = image.getTimeZone();
|
||||
List<String> paths = image.getPaths() == null ? Collections.emptyList() : Arrays.asList(image.getPaths());
|
||||
String md5 = image.getMd5();
|
||||
String sha1 = image.getSha1();
|
||||
String sha256 = image.getSha256();
|
||||
|
||||
return new ImageDetails(unallocSize, size, sectorSize, timeZone, imageType, paths, md5, sha1, sha256);
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datasourcesummary.uiutils;
|
||||
package org.sleuthkit.autopsy.datasourcesummary.datamodel;
|
||||
|
||||
/**
|
||||
* A function that accepts input of type I and outputs type O. This function is
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2019 - 2020 Basis Technology Corp.
|
||||
* Copyright 2019 - 2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.datasourcesummary.datamodel;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
@ -41,7 +42,10 @@ import org.sleuthkit.datamodel.TskData.TSK_FS_META_TYPE_ENUM;
|
||||
* Utilities for getting information about a data source or all data sources
|
||||
* from the case database.
|
||||
*/
|
||||
final class DataSourceInfoUtilities {
|
||||
public final class DataSourceInfoUtilities {
|
||||
|
||||
public static final String COMMA_FORMAT_STR = "#,###";
|
||||
public static final DecimalFormat COMMA_FORMATTER = new DecimalFormat(COMMA_FORMAT_STR);
|
||||
|
||||
/**
|
||||
* Gets a count of tsk_files for a particular datasource.
|
||||
@ -100,7 +104,7 @@ final class DataSourceInfoUtilities {
|
||||
* @throws TskCoreException
|
||||
* @throws SQLException
|
||||
*/
|
||||
static Long getCountOfRegNonSlackFiles(SleuthkitCase skCase, DataSource currentDataSource, String additionalWhere)
|
||||
public static Long getCountOfRegNonSlackFiles(SleuthkitCase skCase, DataSource currentDataSource, String additionalWhere)
|
||||
throws TskCoreException, SQLException {
|
||||
String whereClause = "meta_type=" + TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()
|
||||
+ " AND type<>" + TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType();
|
||||
@ -115,7 +119,7 @@ final class DataSourceInfoUtilities {
|
||||
/**
|
||||
* An interface for handling a result set and returning a value.
|
||||
*/
|
||||
interface ResultSetHandler<T> {
|
||||
public interface ResultSetHandler<T> {
|
||||
|
||||
T process(ResultSet resultset) throws SQLException;
|
||||
}
|
||||
@ -149,14 +153,14 @@ final class DataSourceInfoUtilities {
|
||||
*
|
||||
* @return The clause.
|
||||
*/
|
||||
static String getMetaFlagsContainsStatement(TSK_FS_META_FLAG_ENUM flag) {
|
||||
public static String getMetaFlagsContainsStatement(TSK_FS_META_FLAG_ENUM flag) {
|
||||
return "meta_flags & " + flag.getValue() + " > 0";
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum for specifying the sort order for getAttributes.
|
||||
*/
|
||||
enum SortOrder {
|
||||
public enum SortOrder {
|
||||
DESCENDING,
|
||||
ASCENDING
|
||||
}
|
||||
@ -181,7 +185,7 @@ final class DataSourceInfoUtilities {
|
||||
*
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
static List<BlackboardArtifact> getArtifacts(SleuthkitCase skCase, BlackboardArtifact.Type artifactType, DataSource dataSource, BlackboardAttribute.Type attributeType, SortOrder sortOrder) throws TskCoreException {
|
||||
public static List<BlackboardArtifact> getArtifacts(SleuthkitCase skCase, BlackboardArtifact.Type artifactType, DataSource dataSource, BlackboardAttribute.Type attributeType, SortOrder sortOrder) throws TskCoreException {
|
||||
return getArtifacts(skCase, artifactType, dataSource, attributeType, sortOrder, 0);
|
||||
}
|
||||
|
||||
@ -207,7 +211,7 @@ final class DataSourceInfoUtilities {
|
||||
*
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
static List<BlackboardArtifact> getArtifacts(SleuthkitCase skCase, BlackboardArtifact.Type artifactType, DataSource dataSource, BlackboardAttribute.Type attributeType, SortOrder sortOrder, int maxCount) throws TskCoreException {
|
||||
public static List<BlackboardArtifact> getArtifacts(SleuthkitCase skCase, BlackboardArtifact.Type artifactType, DataSource dataSource, BlackboardAttribute.Type attributeType, SortOrder sortOrder, int maxCount) throws TskCoreException {
|
||||
if (maxCount < 0) {
|
||||
throw new IllegalArgumentException("Invalid maxCount passed to getArtifacts, value must be equal to or greater than 0");
|
||||
}
|
||||
@ -380,7 +384,7 @@ final class DataSourceInfoUtilities {
|
||||
* @return The 'getValueString()' value or null if the attribute or String
|
||||
* could not be retrieved.
|
||||
*/
|
||||
static String getStringOrNull(BlackboardArtifact artifact, Type attributeType) {
|
||||
public static String getStringOrNull(BlackboardArtifact artifact, Type attributeType) {
|
||||
BlackboardAttribute attr = getAttributeOrNull(artifact, attributeType);
|
||||
return (attr == null) ? null : attr.getValueString();
|
||||
}
|
||||
@ -394,7 +398,7 @@ final class DataSourceInfoUtilities {
|
||||
* @return The 'getValueLong()' value or null if the attribute could not be
|
||||
* retrieved.
|
||||
*/
|
||||
static Long getLongOrNull(BlackboardArtifact artifact, Type attributeType) {
|
||||
public static Long getLongOrNull(BlackboardArtifact artifact, Type attributeType) {
|
||||
BlackboardAttribute attr = getAttributeOrNull(artifact, attributeType);
|
||||
return (attr == null) ? null : attr.getValueLong();
|
||||
}
|
||||
@ -408,7 +412,7 @@ final class DataSourceInfoUtilities {
|
||||
* @return The 'getValueInt()' value or null if the attribute could not be
|
||||
* retrieved.
|
||||
*/
|
||||
static Integer getIntOrNull(BlackboardArtifact artifact, Type attributeType) {
|
||||
public static Integer getIntOrNull(BlackboardArtifact artifact, Type attributeType) {
|
||||
BlackboardAttribute attr = getAttributeOrNull(artifact, attributeType);
|
||||
return (attr == null) ? null : attr.getValueInt();
|
||||
}
|
||||
@ -423,8 +427,31 @@ final class DataSourceInfoUtilities {
|
||||
* @return The date determined from the 'getValueLong()' as seconds from
|
||||
* epoch or null if the attribute could not be retrieved or is 0.
|
||||
*/
|
||||
static Date getDateOrNull(BlackboardArtifact artifact, Type attributeType) {
|
||||
public static Date getDateOrNull(BlackboardArtifact artifact, Type attributeType) {
|
||||
Long longVal = getLongOrNull(artifact, attributeType);
|
||||
return (longVal == null || longVal == 0) ? null : new Date(longVal * 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the long value or zero if longVal is null.
|
||||
*
|
||||
* @param longVal The long value.
|
||||
*
|
||||
* @return The long value or 0 if provided value is null.
|
||||
*/
|
||||
public static long getLongOrZero(Long longVal) {
|
||||
return longVal == null ? 0 : longVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns string value of long with comma separators. If null returns a
|
||||
* string of '0'.
|
||||
*
|
||||
* @param longVal The long value.
|
||||
*
|
||||
* @return The string value of the long.
|
||||
*/
|
||||
public static String getStringOrZero(Long longVal) {
|
||||
return longVal == null ? "0" : COMMA_FORMATTER.format(longVal);
|
||||
}
|
||||
}
|
||||
|
46
Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/GeolocationSummary.java
Normal file → Executable file
46
Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/GeolocationSummary.java
Normal file → Executable file
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020 Basis Technology Corp.
|
||||
* Copyright 2020-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -32,7 +32,6 @@ import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor;
|
||||
import org.sleuthkit.autopsy.geolocation.AbstractWaypointFetcher;
|
||||
import org.sleuthkit.autopsy.geolocation.GeoFilter;
|
||||
import org.sleuthkit.autopsy.geolocation.MapWaypoint;
|
||||
@ -45,7 +44,7 @@ import org.sleuthkit.datamodel.DataSource;
|
||||
/**
|
||||
* Gathers summary data about Geolocation information for a data source.
|
||||
*/
|
||||
public class GeolocationSummary implements DefaultArtifactUpdateGovernor {
|
||||
public class GeolocationSummary {
|
||||
|
||||
/**
|
||||
* A count of hits for a particular city.
|
||||
@ -142,8 +141,8 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor {
|
||||
/**
|
||||
* Main constructor.
|
||||
*
|
||||
* @param counts The list of cities and the count of how many points are
|
||||
* closest to that city.
|
||||
* @param counts The list of cities and the count of how many points
|
||||
* are closest to that city.
|
||||
* @param otherCount The count of points where no closest city was
|
||||
* determined due to not being close enough.
|
||||
*/
|
||||
@ -183,10 +182,10 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor {
|
||||
* Main constructor.
|
||||
*
|
||||
* @param mapWaypoints The way points found for the data source.
|
||||
* @param tracks A list of sets where each set is a track in the data
|
||||
* source.
|
||||
* @param areas A list of areas where each set is an area in the data
|
||||
* source.
|
||||
* @param tracks A list of sets where each set is a track in the
|
||||
* data source.
|
||||
* @param areas A list of areas where each set is an area in the
|
||||
* data source.
|
||||
*/
|
||||
private GeoResult(Set<MapWaypoint> mapWaypoints, List<Set<MapWaypoint>> tracks, List<Set<MapWaypoint>> areas) {
|
||||
this.mapWaypoints = mapWaypoints;
|
||||
@ -250,6 +249,7 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor {
|
||||
* A supplier method that can throw an exception of E.
|
||||
*
|
||||
* @return The object type.
|
||||
*
|
||||
* @throws E The exception type.
|
||||
*/
|
||||
T get() throws E;
|
||||
@ -277,13 +277,12 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor {
|
||||
/**
|
||||
* @return Returns all the geolocation artifact types.
|
||||
*/
|
||||
public List<ARTIFACT_TYPE> getGeoTypes() {
|
||||
public static List<ARTIFACT_TYPE> getGeoTypes() {
|
||||
return GPS_ARTIFACT_TYPES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Integer> getArtifactTypeIdsForRefresh() {
|
||||
return GPS_ARTIFACT_TYPE_IDS;
|
||||
public static Set<Integer> getArtifactTypeIdsForRefresh() {
|
||||
return Collections.unmodifiableSet(GPS_ARTIFACT_TYPE_IDS);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -294,10 +293,11 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor {
|
||||
* return false.
|
||||
* @param time The time to check. If null is provided and the min time is
|
||||
* non-null, then this function will return false.
|
||||
*
|
||||
* @return If minTime == null then false. If minTime != null && time == null
|
||||
* then false. Otherwise time >= minTime.
|
||||
*/
|
||||
private boolean greaterThanOrEqual(Long minTime, Long time) {
|
||||
private static boolean greaterThanOrEqual(Long minTime, Long time) {
|
||||
if (minTime != null && time != null && time >= minTime) {
|
||||
return true;
|
||||
} else {
|
||||
@ -312,10 +312,11 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor {
|
||||
*
|
||||
* @param points The list of way points.
|
||||
* @param minTime The minimum time for most recent points count.
|
||||
*
|
||||
* @return A pair where the left value is the total count of way points and
|
||||
* the right is the total list of way points that are >= minTime.
|
||||
*/
|
||||
private Pair<Integer, Integer> getCounts(List<Long> points, Long minTime) {
|
||||
private static Pair<Integer, Integer> getCounts(List<Long> points, Long minTime) {
|
||||
if (points == null) {
|
||||
return EMPTY_COUNT;
|
||||
}
|
||||
@ -333,6 +334,7 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor {
|
||||
*
|
||||
* @param cityMapper The means of mapping a point to the closest city.
|
||||
* @param pt The geolocation point.
|
||||
*
|
||||
* @return A tuple of the closest city and timestamp in seconds from epoch.
|
||||
*/
|
||||
private Pair<CityRecord, Long> getClosestWithTime(ClosestCityMapper cityMapper, MapWaypoint pt) {
|
||||
@ -353,8 +355,10 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor {
|
||||
*
|
||||
* @param points The points in the grouping.
|
||||
* @param cityMapper The means of mapping a point to the closest city.
|
||||
*
|
||||
* @return A stream of tuples where each tuple will be a unique city (or
|
||||
* null if a closest is not determined) and the latest timestamp for each.
|
||||
* null if a closest is not determined) and the latest timestamp for
|
||||
* each.
|
||||
*/
|
||||
private Stream<Pair<CityRecord, Long>> reduceGrouping(Set<MapWaypoint> points, ClosestCityMapper cityMapper) {
|
||||
if (points == null) {
|
||||
@ -387,8 +391,10 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor {
|
||||
*
|
||||
* @param geoResult The result from the Geolocation API.
|
||||
* @param cityMapper The means of mapping a point to the closest city.
|
||||
*
|
||||
* @return A list of tuples where each tuple represents a point to be
|
||||
* counted with a combination of the closest city and the timestamp.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private Stream<Pair<CityRecord, Long>> processGeoResult(GeoResult geoResult, ClosestCityMapper cityMapper) {
|
||||
@ -507,11 +513,12 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor {
|
||||
* Main constructor.
|
||||
*
|
||||
* @param asyncResult Geolocation fetches results in a callback which is
|
||||
* already handled by other mechanisms in data source summary. The
|
||||
* BlockingQueue blocks until a result is received from geolocation.
|
||||
* already handled by other mechanisms in data source
|
||||
* summary. The BlockingQueue blocks until a result
|
||||
* is received from geolocation.
|
||||
* @param filters The applicable filters for geolocation.
|
||||
*/
|
||||
public PointFetcher(BlockingQueue<GeoResult> asyncResult, GeoFilter filters) {
|
||||
PointFetcher(BlockingQueue<GeoResult> asyncResult, GeoFilter filters) {
|
||||
super(filters);
|
||||
this.asyncResult = asyncResult;
|
||||
}
|
||||
@ -531,6 +538,7 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor {
|
||||
* Fetches all GPS data for the data source from the current case.
|
||||
*
|
||||
* @param dataSource The data source.
|
||||
*
|
||||
* @return The GPS data pertaining to the data source.
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws GeoLocationDataException
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020 Basis Technology Corp.
|
||||
* Copyright 2020-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -86,6 +86,7 @@ class LatLngMap<E extends KdTree.XYZPoint> {
|
||||
* closest neighboring buckets.
|
||||
*
|
||||
* @param point The point to calculate the bucket location pair.
|
||||
*
|
||||
* @return The pair that was determined.
|
||||
*/
|
||||
private Pair<Double, Double> getBucketLocation(XYZPoint point) {
|
||||
@ -106,6 +107,7 @@ class LatLngMap<E extends KdTree.XYZPoint> {
|
||||
* Finds closest point within (.5 * bucketSize) distance.
|
||||
*
|
||||
* @param point The point for which to find closest.
|
||||
*
|
||||
* @return Returns the found point.
|
||||
*/
|
||||
E findClosest(E point) {
|
||||
@ -135,6 +137,7 @@ class LatLngMap<E extends KdTree.XYZPoint> {
|
||||
* @param x The x axis bucket.
|
||||
* @param y The y axis bucket.
|
||||
* @param point The point to search for.
|
||||
*
|
||||
* @return The point, if any, that was found.
|
||||
*/
|
||||
private E findClosestInBucket(int x, int y, E point) {
|
||||
|
59
Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/MimeTypeSummary.java
Normal file → Executable file
59
Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/MimeTypeSummary.java
Normal file → Executable file
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020 Basis Technology Corp.
|
||||
* Copyright 2020-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -18,30 +18,22 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datasourcesummary.datamodel;
|
||||
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultUpdateGovernor;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Provides methods to query for datasource files by mime type.
|
||||
* Class to export summary information used by TypesPanel tab on the known files
|
||||
* present in the specified DataSource.
|
||||
*/
|
||||
public class MimeTypeSummary implements DefaultUpdateGovernor {
|
||||
public class MimeTypeSummary {
|
||||
|
||||
private final SleuthkitCaseProvider provider;
|
||||
|
||||
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS = new HashSet<>(
|
||||
Arrays.asList(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED));
|
||||
|
||||
/**
|
||||
* Main constructor.
|
||||
*/
|
||||
@ -58,26 +50,6 @@ public class MimeTypeSummary implements DefaultUpdateGovernor {
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshRequired(ModuleContentEvent evt) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshRequired(AbstractFile file) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshRequired(IngestManager.IngestJobEvent evt) {
|
||||
return (evt != null && INGEST_JOB_EVENTS.contains(evt));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<IngestManager.IngestJobEvent> getIngestJobEventUpdates() {
|
||||
return INGEST_JOB_EVENTS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of files in the case database for the current data source
|
||||
* which have the specified mimetypes.
|
||||
@ -98,12 +70,7 @@ public class MimeTypeSummary implements DefaultUpdateGovernor {
|
||||
*/
|
||||
public Long getCountOfFilesForMimeTypes(DataSource currentDataSource, Set<String> setOfMimeTypes)
|
||||
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
|
||||
|
||||
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(
|
||||
provider.get(),
|
||||
currentDataSource,
|
||||
"mime_type IN " + getSqlSet(setOfMimeTypes)
|
||||
);
|
||||
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), currentDataSource, "mime_type IN " + getSqlSet(setOfMimeTypes));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -124,13 +91,9 @@ public class MimeTypeSummary implements DefaultUpdateGovernor {
|
||||
*/
|
||||
public Long getCountOfFilesNotInMimeTypes(DataSource currentDataSource, Set<String> setOfMimeTypes)
|
||||
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
|
||||
|
||||
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(
|
||||
provider.get(),
|
||||
currentDataSource,
|
||||
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), currentDataSource,
|
||||
"mime_type NOT IN " + getSqlSet(setOfMimeTypes)
|
||||
+ " AND mime_type IS NOT NULL AND mime_type <> '' "
|
||||
);
|
||||
+ " AND mime_type IS NOT NULL AND mime_type <> '' ");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -146,7 +109,6 @@ public class MimeTypeSummary implements DefaultUpdateGovernor {
|
||||
*/
|
||||
public Long getCountOfAllRegularFiles(DataSource dataSource)
|
||||
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
|
||||
|
||||
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), dataSource, null);
|
||||
}
|
||||
|
||||
@ -164,12 +126,7 @@ public class MimeTypeSummary implements DefaultUpdateGovernor {
|
||||
*/
|
||||
public Long getCountOfFilesWithNoMimeType(DataSource currentDataSource)
|
||||
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
|
||||
|
||||
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(
|
||||
provider.get(),
|
||||
currentDataSource,
|
||||
"(mime_type IS NULL OR mime_type = '') "
|
||||
);
|
||||
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), currentDataSource, "(mime_type IS NULL OR mime_type = '') ");
|
||||
}
|
||||
|
||||
/**
|
||||
|
39
Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java
Normal file → Executable file
39
Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java
Normal file → Executable file
@ -32,7 +32,6 @@ import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.centralrepository.ingestmodule.CentralRepoIngestModuleFactory;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
@ -64,7 +63,7 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
* d) The content of that TSK_OTHER_CASES attribute will be of the form
|
||||
* "case1,case2...caseN"
|
||||
*/
|
||||
public class PastCasesSummary implements DefaultArtifactUpdateGovernor {
|
||||
public class PastCasesSummary {
|
||||
|
||||
/**
|
||||
* Return type for results items in the past cases tab.
|
||||
@ -89,14 +88,14 @@ public class PastCasesSummary implements DefaultArtifactUpdateGovernor {
|
||||
* @return Data for the cases with same id table.
|
||||
*/
|
||||
public List<Pair<String, Long>> getSameIdsResults() {
|
||||
return sameIdsResults;
|
||||
return Collections.unmodifiableList(sameIdsResults);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Data for the tagged notable table.
|
||||
*/
|
||||
public List<Pair<String, Long>> getTaggedNotable() {
|
||||
return taggedNotable;
|
||||
return Collections.unmodifiableList(taggedNotable);
|
||||
}
|
||||
}
|
||||
|
||||
@ -147,11 +146,6 @@ public class PastCasesSummary implements DefaultArtifactUpdateGovernor {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Integer> getArtifactTypeIdsForRefresh() {
|
||||
return ARTIFACT_UPDATE_TYPE_IDS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the provided sources for an attribute, aims to determine if one of
|
||||
* those sources is the Central Repository Ingest Module.
|
||||
@ -216,7 +210,7 @@ public class PastCasesSummary implements DefaultArtifactUpdateGovernor {
|
||||
* @return The list of unique cases and their occurrences sorted from max to
|
||||
* min.
|
||||
*/
|
||||
private List<Pair<String, Long>> getCaseCounts(Stream<String> cases) {
|
||||
private static List<Pair<String, Long>> getCaseCounts(Stream<String> cases) {
|
||||
Collection<List<String>> groupedCases = cases
|
||||
// group by case insensitive compare of cases
|
||||
.collect(Collectors.groupingBy((caseStr) -> caseStr.toUpperCase().trim()))
|
||||
@ -243,10 +237,11 @@ public class PastCasesSummary implements DefaultArtifactUpdateGovernor {
|
||||
* @throws TskCoreException
|
||||
* @throws NoCurrentCaseException
|
||||
*/
|
||||
private BlackboardArtifact getParentArtifact(BlackboardArtifact artifact) throws TskCoreException, NoCurrentCaseException {
|
||||
private BlackboardArtifact getParentArtifact(BlackboardArtifact artifact) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException {
|
||||
|
||||
BlackboardArtifact sourceArtifact = null;
|
||||
Content content = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID());
|
||||
SleuthkitCase skCase = caseProvider.get();
|
||||
Content content = skCase.getContentById(artifact.getObjectID());
|
||||
if (content instanceof BlackboardArtifact) {
|
||||
sourceArtifact = (BlackboardArtifact) content;
|
||||
}
|
||||
@ -263,7 +258,7 @@ public class PastCasesSummary implements DefaultArtifactUpdateGovernor {
|
||||
* @throws TskCoreException
|
||||
* @throws NoCurrentCaseException
|
||||
*/
|
||||
private boolean hasDeviceAssociatedArtifact(BlackboardArtifact artifact) throws TskCoreException, NoCurrentCaseException {
|
||||
private boolean hasDeviceAssociatedArtifact(BlackboardArtifact artifact) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException {
|
||||
BlackboardArtifact parent = getParentArtifact(artifact);
|
||||
if (parent == null) {
|
||||
return false;
|
||||
@ -284,7 +279,7 @@ public class PastCasesSummary implements DefaultArtifactUpdateGovernor {
|
||||
* @throws NoCurrentCaseException
|
||||
*/
|
||||
public PastCasesResult getPastCasesData(DataSource dataSource)
|
||||
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, NoCurrentCaseException {
|
||||
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException {
|
||||
|
||||
if (dataSource == null) {
|
||||
return null;
|
||||
@ -294,8 +289,8 @@ public class PastCasesSummary implements DefaultArtifactUpdateGovernor {
|
||||
|
||||
List<String> deviceArtifactCases = new ArrayList<>();
|
||||
List<String> nonDeviceArtifactCases = new ArrayList<>();
|
||||
|
||||
for (BlackboardArtifact artifact : skCase.getBlackboard().getArtifacts(ARTIFACT_TYPE.TSK_PREVIOUSLY_SEEN.getTypeID(), dataSource.getId())) {
|
||||
for (Integer typeId : ARTIFACT_UPDATE_TYPE_IDS) {
|
||||
for (BlackboardArtifact artifact : skCase.getBlackboard().getArtifacts(typeId, dataSource.getId())) {
|
||||
List<String> cases = getCasesFromArtifact(artifact);
|
||||
if (cases == null || cases.isEmpty()) {
|
||||
continue;
|
||||
@ -307,18 +302,6 @@ public class PastCasesSummary implements DefaultArtifactUpdateGovernor {
|
||||
nonDeviceArtifactCases.addAll(cases);
|
||||
}
|
||||
}
|
||||
|
||||
for (BlackboardArtifact artifact : skCase.getBlackboard().getArtifacts(ARTIFACT_TYPE.TSK_PREVIOUSLY_NOTABLE.getTypeID(), dataSource.getId())) {
|
||||
List<String> cases = getCasesFromArtifact(artifact);
|
||||
if (cases == null || cases.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hasDeviceAssociatedArtifact(artifact)) {
|
||||
deviceArtifactCases.addAll(cases);
|
||||
} else {
|
||||
nonDeviceArtifactCases.addAll(cases);
|
||||
}
|
||||
}
|
||||
|
||||
return new PastCasesResult(
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020 Basis Technology Corp.
|
||||
* Copyright 2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -18,21 +18,18 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datasourcesummary.datamodel;
|
||||
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor;
|
||||
import java.nio.file.Paths;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
@ -40,13 +37,12 @@ import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||
|
||||
/**
|
||||
* Helper class for getting data for the Recent Files Data Summary tab.
|
||||
* Helper class for getting Recent Activity data.
|
||||
*/
|
||||
public class RecentFilesSummary implements DefaultArtifactUpdateGovernor {
|
||||
public class RecentFilesSummary {
|
||||
|
||||
private final static BlackboardAttribute.Type DATETIME_ACCESSED_ATT = new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED);
|
||||
private final static BlackboardAttribute.Type DOMAIN_ATT = new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN);
|
||||
@ -58,14 +54,6 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor {
|
||||
|
||||
private static final DateFormat DATETIME_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.getDefault());
|
||||
|
||||
private static final Set<Integer> ARTIFACT_UPDATE_TYPE_IDS = new HashSet<>(Arrays.asList(
|
||||
ARTIFACT_TYPE.TSK_RECENT_OBJECT.getTypeID(),
|
||||
ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID(),
|
||||
ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT.getTypeID(),
|
||||
ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID(),
|
||||
ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()
|
||||
));
|
||||
|
||||
private final SleuthkitCaseProvider provider;
|
||||
|
||||
/**
|
||||
@ -88,11 +76,6 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor {
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Integer> getArtifactTypeIdsForRefresh() {
|
||||
return ARTIFACT_UPDATE_TYPE_IDS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes fileDetails entries with redundant paths, sorts by date
|
||||
* descending and limits to the limit provided.
|
||||
@ -101,7 +84,7 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor {
|
||||
* @param limit The maximum number of entries to return.
|
||||
* @return The sorted limited list with unique paths.
|
||||
*/
|
||||
private <T extends RecentFileDetails> List<T> getSortedLimited(List<T> fileDetails, int limit) {
|
||||
private static <T extends RecentFileDetails> List<T> getSortedLimited(List<T> fileDetails, int limit) {
|
||||
Map<String, T> fileDetailsMap = fileDetails.stream()
|
||||
.filter(details -> details != null)
|
||||
.collect(Collectors.toMap(
|
||||
@ -122,7 +105,7 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor {
|
||||
* @param artifact The artifact.
|
||||
* @return The derived object or null if artifact is invalid.
|
||||
*/
|
||||
private RecentFileDetails getRecentlyOpenedDocument(BlackboardArtifact artifact) {
|
||||
private static RecentFileDetails getRecentlyOpenedDocument(BlackboardArtifact artifact) {
|
||||
String path = DataSourceInfoUtilities.getStringOrNull(artifact, PATH_ATT);
|
||||
Long lastOpened = DataSourceInfoUtilities.getLongOrNull(artifact, DATETIME_ACCESSED_ATT);
|
||||
|
||||
@ -170,7 +153,7 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor {
|
||||
* @param artifact The artifact.
|
||||
* @return The derived object or null if artifact is invalid.
|
||||
*/
|
||||
private RecentDownloadDetails getRecentDownload(BlackboardArtifact artifact) {
|
||||
private static RecentDownloadDetails getRecentDownload(BlackboardArtifact artifact) {
|
||||
Long accessedTime = DataSourceInfoUtilities.getLongOrNull(artifact, DATETIME_ACCESSED_ATT);
|
||||
String domain = DataSourceInfoUtilities.getStringOrNull(artifact, DOMAIN_ATT);
|
||||
String path = DataSourceInfoUtilities.getStringOrNull(artifact, PATH_ATT);
|
||||
@ -187,7 +170,7 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor {
|
||||
*
|
||||
* @param count The count.
|
||||
*/
|
||||
private void throwOnNonPositiveCount(int count) {
|
||||
private static void throwOnNonPositiveCount(int count) {
|
||||
if (count < 1) {
|
||||
throw new IllegalArgumentException("Invalid count: value must be greater than 0.");
|
||||
}
|
||||
@ -268,7 +251,7 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor {
|
||||
* @return The derived object or null.
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
private RecentAttachmentDetails getRecentAttachment(BlackboardArtifact artifact, SleuthkitCase skCase) throws TskCoreException {
|
||||
private static RecentAttachmentDetails getRecentAttachment(BlackboardArtifact artifact, SleuthkitCase skCase) throws TskCoreException {
|
||||
// get associated artifact or return no result
|
||||
BlackboardAttribute attribute = artifact.getAttribute(ASSOCATED_ATT);
|
||||
if (attribute == null) {
|
||||
@ -309,7 +292,7 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor {
|
||||
*
|
||||
* @return True if the given artifact is a message artifact
|
||||
*/
|
||||
private boolean isMessageArtifact(BlackboardArtifact nodeArtifact) {
|
||||
private static boolean isMessageArtifact(BlackboardArtifact nodeArtifact) {
|
||||
final int artifactTypeID = nodeArtifact.getArtifactTypeID();
|
||||
return artifactTypeID == ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()
|
||||
|| artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID();
|
||||
|
0
Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/SleuthkitCaseProvider.java
Normal file → Executable file
0
Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/SleuthkitCaseProvider.java
Normal file → Executable file
7
Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineDataSourceUtils.java
Normal file → Executable file
7
Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineDataSourceUtils.java
Normal file → Executable file
@ -18,7 +18,6 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datasourcesummary.datamodel;
|
||||
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.timeline.TimeLineController;
|
||||
import org.sleuthkit.autopsy.timeline.TimeLineModule;
|
||||
import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.FilterState;
|
||||
@ -60,10 +59,9 @@ public class TimelineDataSourceUtils {
|
||||
* @param dataSource The data source.
|
||||
* @return The root filter representing a default filter with only this data
|
||||
* source selected.
|
||||
* @throws NoCurrentCaseException
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public RootFilter getDataSourceFilter(DataSource dataSource) throws NoCurrentCaseException, TskCoreException {
|
||||
public RootFilter getDataSourceFilter(DataSource dataSource) throws TskCoreException {
|
||||
RootFilterState filterState = getDataSourceFilterState(dataSource);
|
||||
return filterState == null ? null : filterState.getActiveFilter();
|
||||
}
|
||||
@ -75,10 +73,9 @@ public class TimelineDataSourceUtils {
|
||||
* @param dataSource The data source.
|
||||
* @return The root filter state representing a default filter with only
|
||||
* this data source selected.
|
||||
* @throws NoCurrentCaseException
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public RootFilterState getDataSourceFilterState(DataSource dataSource) throws NoCurrentCaseException, TskCoreException {
|
||||
public RootFilterState getDataSourceFilterState(DataSource dataSource) throws TskCoreException {
|
||||
TimeLineController controller = TimeLineModule.getController();
|
||||
RootFilterState dataSourceState = controller.getEventsModel().getDefaultEventFilterState().copyOf();
|
||||
|
||||
|
98
Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummary.java
Normal file → Executable file
98
Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummary.java
Normal file → Executable file
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020 Basis Technology Corp.
|
||||
* Copyright 2020-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -18,6 +18,8 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datasourcesummary.datamodel;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -26,29 +28,25 @@ import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import org.joda.time.Interval;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultUpdateGovernor;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import org.sleuthkit.datamodel.TimelineEvent;
|
||||
import org.sleuthkit.datamodel.TimelineEventType;
|
||||
import org.sleuthkit.datamodel.TimelineFilter.RootFilter;
|
||||
import org.sleuthkit.datamodel.TimelineManager;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
|
||||
import java.util.function.Supplier;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
|
||||
/**
|
||||
* Provides data source summary information pertaining to Timeline data.
|
||||
*/
|
||||
public class TimelineSummary implements DefaultUpdateGovernor {
|
||||
public class TimelineSummary {
|
||||
|
||||
/**
|
||||
* A function for obtaining a Timeline RootFilter filtered to the specific
|
||||
@ -61,16 +59,13 @@ public class TimelineSummary implements DefaultUpdateGovernor {
|
||||
*
|
||||
* @param dataSource The data source.
|
||||
* @return The timeline root filter.
|
||||
* @throws NoCurrentCaseException
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
RootFilter apply(DataSource dataSource) throws NoCurrentCaseException, TskCoreException;
|
||||
RootFilter apply(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException;
|
||||
}
|
||||
|
||||
private static final long DAY_SECS = 24 * 60 * 60;
|
||||
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS = new HashSet<>(
|
||||
Arrays.asList(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED));
|
||||
|
||||
private static final Set<TimelineEventType> FILE_SYSTEM_EVENTS
|
||||
= new HashSet<>(Arrays.asList(
|
||||
TimelineEventType.FILE_MODIFIED,
|
||||
@ -105,26 +100,6 @@ public class TimelineSummary implements DefaultUpdateGovernor {
|
||||
this.filterFunction = filterFunction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshRequired(ModuleContentEvent evt) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshRequired(AbstractFile file) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshRequired(IngestManager.IngestJobEvent evt) {
|
||||
return (evt != null && INGEST_JOB_EVENTS.contains(evt));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<IngestManager.IngestJobEvent> getIngestJobEventUpdates() {
|
||||
return INGEST_JOB_EVENTS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves timeline summary data.
|
||||
*
|
||||
@ -132,12 +107,12 @@ public class TimelineSummary implements DefaultUpdateGovernor {
|
||||
* retrieved.
|
||||
* @param recentDaysNum The maximum number of most recent days' activity to
|
||||
* include.
|
||||
*
|
||||
* @return The retrieved data.
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
* @throws NoCurrentCaseException
|
||||
*/
|
||||
public TimelineSummaryData getData(DataSource dataSource, int recentDaysNum) throws SleuthkitCaseProviderException, TskCoreException, NoCurrentCaseException {
|
||||
public TimelineSummaryData getTimelineSummaryData(DataSource dataSource, int recentDaysNum) throws SleuthkitCaseProviderException, TskCoreException {
|
||||
TimeZone timeZone = this.timeZoneProvider.get();
|
||||
TimelineManager timelineManager = this.caseProvider.get().getTimelineManager();
|
||||
|
||||
@ -174,10 +149,11 @@ public class TimelineSummary implements DefaultUpdateGovernor {
|
||||
* Given activity by day, converts to most recent days' activity handling
|
||||
* empty values.
|
||||
*
|
||||
* @param dateCounts The day from epoch mapped to activity amounts for that
|
||||
* day.
|
||||
* @param dateCounts The day from epoch mapped to activity amounts for
|
||||
* that day.
|
||||
* @param minRecentDay The minimum recent day in days from epoch.
|
||||
* @param maxDay The maximum recent day in days from epoch;
|
||||
*
|
||||
* @return The most recent daily activity amounts.
|
||||
*/
|
||||
private List<DailyActivityAmount> getMostRecentActivityAmounts(Map<Long, DailyActivityAmount> dateCounts, long minRecentDay, long maxDay) {
|
||||
@ -200,14 +176,15 @@ public class TimelineSummary implements DefaultUpdateGovernor {
|
||||
* @param dataSource The data source.
|
||||
* @param timelineManager The timeline manager to use while fetching the
|
||||
* data.
|
||||
* @param timeZone The time zone to use to determine which day activity
|
||||
* belongs.
|
||||
* @param timeZone The time zone to use to determine which day
|
||||
* activity belongs.
|
||||
*
|
||||
* @return A Map mapping days from epoch to the activity for that day.
|
||||
*
|
||||
* @throws TskCoreException
|
||||
* @throws NoCurrentCaseException
|
||||
*/
|
||||
private Map<Long, DailyActivityAmount> getTimelineEventsByDay(DataSource dataSource, TimelineManager timelineManager, TimeZone timeZone)
|
||||
throws TskCoreException, NoCurrentCaseException {
|
||||
throws TskCoreException, SleuthkitCaseProviderException {
|
||||
RootFilter rootFilter = this.filterFunction.apply(dataSource);
|
||||
|
||||
// get events for data source
|
||||
@ -251,12 +228,14 @@ public class TimelineSummary implements DefaultUpdateGovernor {
|
||||
/**
|
||||
* Main constructor.
|
||||
*
|
||||
* @param minDate Earliest usage date recorded for the data source.
|
||||
* @param maxDate Latest usage date recorded for the data source.
|
||||
* @param minDate Earliest usage date recorded for the data
|
||||
* source.
|
||||
* @param maxDate Latest usage date recorded for the data
|
||||
* source.
|
||||
* @param recentDaysActivity A list of activity prior to and including
|
||||
* max date sorted by min to max date.
|
||||
* @param dataSource The data source for which this data applies. the
|
||||
* latest usage date by day.
|
||||
* @param dataSource The data source for which this data
|
||||
* applies. the latest usage date by day.
|
||||
*/
|
||||
TimelineSummaryData(Date minDate, Date maxDate, List<DailyActivityAmount> recentDaysActivity, DataSource dataSource) {
|
||||
this.minDate = minDate;
|
||||
@ -307,8 +286,10 @@ public class TimelineSummary implements DefaultUpdateGovernor {
|
||||
/**
|
||||
* Main constructor.
|
||||
*
|
||||
* @param day The day for which activity is being measured.
|
||||
* @param fileActivityCount The amount of file activity timeline events.
|
||||
* @param day The day for which activity is being
|
||||
* measured.
|
||||
* @param fileActivityCount The amount of file activity timeline
|
||||
* events.
|
||||
* @param artifactActivityCount The amount of artifact timeline events.
|
||||
*/
|
||||
DailyActivityAmount(Date day, long fileActivityCount, long artifactActivityCount) {
|
||||
@ -337,6 +318,29 @@ public class TimelineSummary implements DefaultUpdateGovernor {
|
||||
public long getArtifactActivityCount() {
|
||||
return artifactActivityCount;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a DateFormat formatter that uses UTC for time zone.
|
||||
*
|
||||
* @param formatString The date format string.
|
||||
* @return The data format.
|
||||
*/
|
||||
public static DateFormat getUtcFormat(String formatString) {
|
||||
return new SimpleDateFormat(formatString, Locale.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a date using a DateFormat. In the event that the date is null,
|
||||
* returns a null string.
|
||||
*
|
||||
* @param date The date to format.
|
||||
* @param formatter The DateFormat to use to format the date.
|
||||
*
|
||||
* @return The formatted string generated from the formatter or null if the
|
||||
* date is null.
|
||||
*/
|
||||
public static String formatDate(Date date, DateFormat formatter) {
|
||||
return date == null ? null : formatter.format(date);
|
||||
}
|
||||
}
|
||||
|
93
Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TypesSummary.java
Normal file → Executable file
93
Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TypesSummary.java
Normal file → Executable file
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2019 - 2020 Basis Technology Corp.
|
||||
* Copyright 2019 - 2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -18,26 +18,19 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datasourcesummary.datamodel;
|
||||
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultUpdateGovernor;
|
||||
import java.awt.Color;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.autopsy.coreutils.FileTypeUtils;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
/**
|
||||
* Provides information for the DataSourceSummaryCountsPanel.
|
||||
* Helper class for getting summary information on the known files present in the
|
||||
* specified DataSource..
|
||||
*/
|
||||
public class TypesSummary implements DefaultUpdateGovernor {
|
||||
|
||||
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS = new HashSet<>(
|
||||
Arrays.asList(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED));
|
||||
public class TypesSummary {
|
||||
|
||||
private final SleuthkitCaseProvider provider;
|
||||
|
||||
@ -57,25 +50,6 @@ public class TypesSummary implements DefaultUpdateGovernor {
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshRequired(ModuleContentEvent evt) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshRequired(AbstractFile file) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshRequired(IngestManager.IngestJobEvent evt) {
|
||||
return (evt != null && INGEST_JOB_EVENTS.contains(evt));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<IngestManager.IngestJobEvent> getIngestJobEventUpdates() {
|
||||
return INGEST_JOB_EVENTS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get count of regular files (not directories) in a data source.
|
||||
@ -169,4 +143,59 @@ public class TypesSummary implements DefaultUpdateGovernor {
|
||||
return DataSourceInfoUtilities.getCountOfRegularFiles(provider.get(), currentDataSource,
|
||||
"type=" + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Information concerning a particular file type category.
|
||||
*/
|
||||
public static class FileTypeCategoryData {
|
||||
|
||||
private final String label;
|
||||
private final Set<String> mimeTypes;
|
||||
private final Color color;
|
||||
|
||||
/**
|
||||
* Main constructor.
|
||||
*
|
||||
* @param label The label for this slice.
|
||||
* @param mimeTypes The mime types associated with this slice.
|
||||
* @param color The color associated with this slice.
|
||||
*/
|
||||
public FileTypeCategoryData(String label, Set<String> mimeTypes, Color color) {
|
||||
this.label = label;
|
||||
this.mimeTypes = mimeTypes;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that accepts FileTypeCategory.
|
||||
*
|
||||
* @param label The label for this slice.
|
||||
* @param mimeTypes The mime types associated with this slice.
|
||||
* @param color The color associated with this slice.
|
||||
*/
|
||||
public FileTypeCategoryData(String label, FileTypeUtils.FileTypeCategory fileCategory, Color color) {
|
||||
this(label, fileCategory.getMediaTypes(), color);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The label for this category.
|
||||
*/
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The mime types associated with this category.
|
||||
*/
|
||||
public Set<String> getMimeTypes() {
|
||||
return mimeTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The color associated with this category.
|
||||
*/
|
||||
public Color getColor() {
|
||||
return color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
105
Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java
Normal file → Executable file
105
Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java
Normal file → Executable file
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020 Basis Technology Corp.
|
||||
* Copyright 2020-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -19,7 +19,6 @@
|
||||
package org.sleuthkit.autopsy.datasourcesummary.datamodel;
|
||||
|
||||
import java.io.File;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@ -54,7 +53,7 @@ import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
||||
* time, the data being provided for domains is fictitious and is done as a
|
||||
* placeholder.
|
||||
*/
|
||||
public class UserActivitySummary implements DefaultArtifactUpdateGovernor {
|
||||
public class UserActivitySummary {
|
||||
|
||||
/**
|
||||
* Functions that determine the folder name of a list of path elements. If
|
||||
@ -138,16 +137,6 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor {
|
||||
.compareToIgnoreCase((b.getProgramName() == null ? "" : b.getProgramName()));
|
||||
};
|
||||
|
||||
private static final Set<Integer> ARTIFACT_UPDATE_TYPE_IDS = new HashSet<>(Arrays.asList(
|
||||
ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID(),
|
||||
ARTIFACT_TYPE.TSK_MESSAGE.getTypeID(),
|
||||
ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID(),
|
||||
ARTIFACT_TYPE.TSK_CALLLOG.getTypeID(),
|
||||
ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID(),
|
||||
ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID(),
|
||||
ARTIFACT_TYPE.TSK_PROG_RUN.getTypeID()
|
||||
));
|
||||
|
||||
private static final Set<String> DEVICE_EXCLUDE_LIST = new HashSet<>(Arrays.asList("ROOT_HUB", "ROOT_HUB20"));
|
||||
private static final Set<String> DOMAIN_EXCLUDE_LIST = new HashSet<>(Arrays.asList("127.0.0.1", "LOCALHOST"));
|
||||
|
||||
@ -186,22 +175,50 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Integer> getArtifactTypeIdsForRefresh() {
|
||||
return ARTIFACT_UPDATE_TYPE_IDS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an IllegalArgumentException if count <= 0.
|
||||
*
|
||||
* @param count The count being checked.
|
||||
*/
|
||||
private void assertValidCount(int count) {
|
||||
private static void assertValidCount(int count) {
|
||||
if (count <= 0) {
|
||||
throw new IllegalArgumentException("Count must be greater than 0");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines a short folder name if any. Otherwise, returns empty string.
|
||||
*
|
||||
* @param strPath The string path.
|
||||
* @param applicationName The application name.
|
||||
*
|
||||
* @return The short folder name or empty string if not found.
|
||||
*/
|
||||
public static String getShortFolderName(String strPath, String applicationName) {
|
||||
if (strPath == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
List<String> pathEls = new ArrayList<>(Arrays.asList(applicationName));
|
||||
|
||||
File file = new File(strPath);
|
||||
while (file != null && org.apache.commons.lang.StringUtils.isNotBlank(file.getName())) {
|
||||
pathEls.add(file.getName());
|
||||
file = file.getParentFile();
|
||||
}
|
||||
|
||||
Collections.reverse(pathEls);
|
||||
|
||||
for (Function<List<String>, String> matchEntry : SHORT_FOLDER_MATCHERS) {
|
||||
String result = matchEntry.apply(pathEls);
|
||||
if (org.apache.commons.lang.StringUtils.isNotBlank(result)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of recent domains based on the datasource.
|
||||
*
|
||||
@ -288,9 +305,9 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor {
|
||||
* @param dataSource The datasource.
|
||||
*
|
||||
* @return A tuple where the first value is the latest web history accessed
|
||||
* date in milliseconds and the second value maps normalized (lowercase;
|
||||
* trimmed) domain names to when those domains were visited and the relevant
|
||||
* artifact.
|
||||
* date in milliseconds and the second value maps normalized
|
||||
* (lowercase; trimmed) domain names to when those domains were
|
||||
* visited and the relevant artifact.
|
||||
*
|
||||
* @throws TskCoreException
|
||||
* @throws SleuthkitCaseProviderException
|
||||
@ -372,7 +389,8 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor {
|
||||
* term.
|
||||
*
|
||||
* @param dataSource The data source.
|
||||
* @param count The maximum number of records to be shown (must be > 0).
|
||||
* @param count The maximum number of records to be shown (must be >
|
||||
* 0).
|
||||
*
|
||||
* @return The list of most recent web searches where most recent search
|
||||
* appears first.
|
||||
@ -462,6 +480,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor {
|
||||
*
|
||||
* @param r1 A result.
|
||||
* @param r2 Another result.
|
||||
*
|
||||
* @return The most recent one with a non-null date.
|
||||
*/
|
||||
private TopDeviceAttachedResult getMostRecentDevice(TopDeviceAttachedResult r1, TopDeviceAttachedResult r2) {
|
||||
@ -480,7 +499,8 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor {
|
||||
* Retrieves most recent devices used by most recent date attached.
|
||||
*
|
||||
* @param dataSource The data source.
|
||||
* @param count The maximum number of records to be shown (must be > 0).
|
||||
* @param count The maximum number of records to be shown (must be >
|
||||
* 0).
|
||||
*
|
||||
* @return The list of most recent devices attached where most recent device
|
||||
* attached appears first.
|
||||
@ -638,39 +658,6 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines a short folder name if any. Otherwise, returns empty string.
|
||||
*
|
||||
* @param strPath The string path.
|
||||
* @param applicationName The application name.
|
||||
*
|
||||
* @return The short folder name or empty string if not found.
|
||||
*/
|
||||
public String getShortFolderName(String strPath, String applicationName) {
|
||||
if (strPath == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
List<String> pathEls = new ArrayList<>(Arrays.asList(applicationName));
|
||||
|
||||
File file = new File(strPath);
|
||||
while (file != null && org.apache.commons.lang.StringUtils.isNotBlank(file.getName())) {
|
||||
pathEls.add(file.getName());
|
||||
file = file.getParentFile();
|
||||
}
|
||||
|
||||
Collections.reverse(pathEls);
|
||||
|
||||
for (Function<List<String>, String> matchEntry : SHORT_FOLDER_MATCHERS) {
|
||||
String result = matchEntry.apply(pathEls);
|
||||
if (org.apache.commons.lang.StringUtils.isNotBlank(result)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a TopProgramsResult from a TSK_PROG_RUN blackboard artifact.
|
||||
*
|
||||
@ -765,8 +752,8 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor {
|
||||
*
|
||||
* @param dataSource The datasource. If the datasource is null, an empty
|
||||
* list will be returned.
|
||||
* @param count The number of results to return. This value must be > 0 or
|
||||
* an IllegalArgumentException will be thrown.
|
||||
* @param count The number of results to return. This value must be > 0
|
||||
* or an IllegalArgumentException will be thrown.
|
||||
*
|
||||
* @return The sorted list and limited to the count if last run or run count
|
||||
* information is available on any item.
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020 Basis Technology Corp.
|
||||
* Copyright 2020-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -21,16 +21,12 @@ package org.sleuthkit.autopsy.datasourcesummary.ui;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.AnalysisSummary;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelSheetExport;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
@ -101,10 +97,10 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel {
|
||||
* Creates a new DataSourceUserActivityPanel.
|
||||
*/
|
||||
public AnalysisPanel() {
|
||||
this(new AnalysisSummary());
|
||||
this(new AnalysisSummaryGetter());
|
||||
}
|
||||
|
||||
public AnalysisPanel(AnalysisSummary analysisData) {
|
||||
public AnalysisPanel(AnalysisSummaryGetter analysisData) {
|
||||
super(analysisData);
|
||||
|
||||
hashsetsFetcher = (dataSource) -> analysisData.getHashsetCounts(dataSource);
|
||||
@ -229,17 +225,6 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel {
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
@Override
|
||||
List<ExcelSheetExport> getExports(DataSource dataSource) {
|
||||
return Stream.of(
|
||||
getTableExport(hashsetsFetcher, DEFAULT_COLUMNS, Bundle.AnalysisPanel_hashsetHits_tabName(), dataSource),
|
||||
getTableExport(keywordsFetcher, DEFAULT_COLUMNS, Bundle.AnalysisPanel_keywordHits_tabName(), dataSource),
|
||||
getTableExport(interestingItemsFetcher, DEFAULT_COLUMNS, Bundle.AnalysisPanel_interestingItemHits_tabName(), dataSource))
|
||||
.filter(sheet -> sheet != null)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
||||
|
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020-2021 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.datasourcesummary.ui;
|
||||
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.AnalysisSummary;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Wrapper class for converting
|
||||
* org.sleuthkit.autopsy.contentutils.AnalysisSummary functionality into a
|
||||
* DefaultArtifactUpdateGovernor used by data source analysis tab.
|
||||
*/
|
||||
public class AnalysisSummaryGetter implements DefaultArtifactUpdateGovernor {
|
||||
|
||||
private static final Set<Integer> ARTIFACT_UPDATE_TYPE_IDS = new HashSet<>(Arrays.asList(
|
||||
ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(),
|
||||
ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID(),
|
||||
ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID(),
|
||||
ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()
|
||||
));
|
||||
|
||||
private final AnalysisSummary analysisSummary;
|
||||
|
||||
/**
|
||||
* Main constructor.
|
||||
*/
|
||||
public AnalysisSummaryGetter() {
|
||||
analysisSummary = new AnalysisSummary();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Integer> getArtifactTypeIdsForRefresh() {
|
||||
return Collections.unmodifiableSet(ARTIFACT_UPDATE_TYPE_IDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets counts for hashset hits.
|
||||
*
|
||||
* @param dataSource The datasource for which to identify hashset hits.
|
||||
*
|
||||
* @return The hashset set name with the number of hits in descending order.
|
||||
*
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public List<Pair<String, Long>> getHashsetCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException {
|
||||
return analysisSummary.getHashsetCounts(dataSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets counts for keyword hits.
|
||||
*
|
||||
* @param dataSource The datasource for which to identify keyword hits.
|
||||
*
|
||||
* @return The keyword set name with the number of hits in descending order.
|
||||
*
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public List<Pair<String, Long>> getKeywordCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException {
|
||||
return analysisSummary.getKeywordCounts(dataSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets counts for interesting item hits.
|
||||
*
|
||||
* @param dataSource The datasource for which to identify interesting item
|
||||
* hits.
|
||||
*
|
||||
* @return The interesting item set name with the number of hits in
|
||||
* descending order.
|
||||
*
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public List<Pair<String, Long>> getInterestingItemCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException {
|
||||
return analysisSummary.getInterestingItemCounts(dataSource);
|
||||
}
|
||||
}
|
@ -38,16 +38,11 @@ import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.EventUpdateHandler;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelExportException;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelSheetExport;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelTableExport;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelCellModel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.GuiCellModel.DefaultMenuItem;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.GuiCellModel.MenuItem;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableComponent;
|
||||
@ -453,14 +448,6 @@ abstract class BaseDataSourceSummaryPanel extends JPanel {
|
||||
*/
|
||||
protected abstract void onNewDataSource(DataSource dataSource);
|
||||
|
||||
/**
|
||||
* Returns all the excel exportable items associated with the tab.
|
||||
*
|
||||
* @param dataSource The data source that results should be filtered.
|
||||
* @return The excel exportable objects.
|
||||
*/
|
||||
abstract List<ExcelSheetExport> getExports(DataSource dataSource);
|
||||
|
||||
/**
|
||||
* Runs a data fetcher and returns the result handling any possible errors
|
||||
* with a log message.
|
||||
@ -485,100 +472,6 @@ abstract class BaseDataSourceSummaryPanel extends JPanel {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that converts data into a excel sheet data.
|
||||
*/
|
||||
protected interface ExcelExportFunction<T> {
|
||||
|
||||
/**
|
||||
* Function that converts data into an excel sheet.
|
||||
*
|
||||
* @param data The data.
|
||||
* @return The excel sheet export.
|
||||
* @throws ExcelExportException
|
||||
*/
|
||||
ExcelSheetExport convert(T data) throws ExcelExportException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method that converts data into an excel sheet export handling
|
||||
* possible excel exceptions.
|
||||
*
|
||||
* @param excelConverter Function to convert data to an excel sheet export.
|
||||
* @param data The data. If data is null, null will be returned.
|
||||
* @param sheetName The name(s) of the sheet (to be used in the error
|
||||
* message).
|
||||
* @return The excel sheet export.
|
||||
*/
|
||||
protected static <T> ExcelSheetExport convertToExcel(ExcelExportFunction<T> excelConverter, T data, String sheetName) {
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return excelConverter.convert(data);
|
||||
} catch (ExcelExportException ex) {
|
||||
logger.log(Level.WARNING,
|
||||
String.format("There was an error while preparing export of worksheet(s): '%s'",
|
||||
sheetName == null ? "<null>" : sheetName), ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an excel sheet export given the fetching of data or null if no
|
||||
* export created.
|
||||
*
|
||||
* @param dataFetcher The means of fetching data.
|
||||
* @param excelConverter The means of converting data to excel.
|
||||
* @param sheetName The name of the sheet (for error handling reporting).
|
||||
* @param ds The data source to use for fetching data.
|
||||
* @return The excel sheet export or null if no export could be generated.
|
||||
*/
|
||||
protected static <T> ExcelSheetExport getExport(
|
||||
DataFetcher<DataSource, T> dataFetcher, ExcelExportFunction<T> excelConverter,
|
||||
String sheetName, DataSource ds) {
|
||||
|
||||
T data = getFetchResult(dataFetcher, sheetName, ds);
|
||||
return convertToExcel(excelConverter, data, sheetName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an excel table export of the data or null if no export created.
|
||||
*
|
||||
* @param columnsModel The model for the columns.
|
||||
* @param sheetName The name for the sheet.
|
||||
* @param data The data to be exported.
|
||||
* @return The excel table export or null if no export could be generated.
|
||||
*/
|
||||
protected static <T, C extends ExcelCellModel> ExcelSheetExport getTableExport(List<ColumnModel<T, C>> columnsModel,
|
||||
String sheetName, List<T> data) {
|
||||
|
||||
return convertToExcel((dataList) -> new ExcelTableExport<T, C>(sheetName, columnsModel, dataList),
|
||||
data,
|
||||
sheetName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an excel table export of the data or null if no export created.
|
||||
*
|
||||
* @param dataFetcher The means of fetching data for the data source and the
|
||||
* export.
|
||||
* @param columnsModel The model for the columns.
|
||||
* @param sheetName The name for the sheet.
|
||||
* @param ds The data source.
|
||||
* @return The excel export or null if no export created.
|
||||
*/
|
||||
protected static <T, C extends ExcelCellModel> ExcelSheetExport getTableExport(
|
||||
DataFetcher<DataSource, List<T>> dataFetcher, List<ColumnModel<T, C>> columnsModel,
|
||||
String sheetName, DataSource ds) {
|
||||
|
||||
return getExport(dataFetcher,
|
||||
(dataList) -> new ExcelTableExport<T, C>(sheetName, columnsModel, dataList),
|
||||
sheetName,
|
||||
ds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method that shows a loading screen with loadable components,
|
||||
* create swing workers from the datafetch components and data source
|
||||
|
@ -6,19 +6,6 @@ AnalysisPanel_keywordHits_tabName=Keyword Hits
|
||||
AnalysisPanel_keywordSearchModuleName=Keyword Search
|
||||
BaseDataSourceSummaryPanel_goToArtifact=View Source Result
|
||||
BaseDataSourceSummaryPanel_goToFile=View Source File in Directory
|
||||
ContainerPanel_export_acquisitionDetails=Acquisition Details:
|
||||
ContainerPanel_export_deviceId=Device ID:
|
||||
ContainerPanel_export_displayName=Display Name:
|
||||
ContainerPanel_export_filePaths=File Paths:
|
||||
ContainerPanel_export_imageType=Image Type:
|
||||
ContainerPanel_export_md5=MD5:
|
||||
ContainerPanel_export_originalName=Name:
|
||||
ContainerPanel_export_sectorSize=Sector Size:
|
||||
ContainerPanel_export_sha1=SHA1:
|
||||
ContainerPanel_export_sha256=SHA256:
|
||||
ContainerPanel_export_size=Size:
|
||||
ContainerPanel_export_timeZone=Time Zone:
|
||||
ContainerPanel_export_unallocatedSize=Unallocated Space:
|
||||
ContainerPanel_setFieldsForNonImageDataSource_na=N/A
|
||||
ContainerPanel_tabName=Container
|
||||
CTL_DataSourceSummaryAction=Data Source Summary
|
||||
@ -62,7 +49,6 @@ DataSourceSummaryNode.column.type.header=Type
|
||||
DataSourceSummaryNode.viewDataSourceAction.text=Go to Data Source
|
||||
DataSourceSummaryTabbedPane_analysisTab_title=Analysis
|
||||
DataSourceSummaryTabbedPane_detailsTab_title=Container
|
||||
DataSourceSummaryTabbedPane_exportTab_title=Export
|
||||
DataSourceSummaryTabbedPane_geolocationTab_title=Geolocation
|
||||
DataSourceSummaryTabbedPane_ingestHistoryTab_title=Ingest History
|
||||
DataSourceSummaryTabbedPane_pastCasesTab_title=Past Cases
|
||||
@ -70,45 +56,27 @@ DataSourceSummaryTabbedPane_recentFileTab_title=Recent Files
|
||||
DataSourceSummaryTabbedPane_timelineTab_title=Timeline
|
||||
DataSourceSummaryTabbedPane_typesTab_title=Types
|
||||
DataSourceSummaryTabbedPane_userActivityTab_title=User Activity
|
||||
ExcelExportAction_exportToXLSX_beginExport=Beginning Export...
|
||||
# {0} - tabName
|
||||
ExcelExportAction_exportToXLSX_gatheringTabData=Fetching Data for {0} Tab...
|
||||
ExcelExportAction_exportToXLSX_writingToFile=Writing to File...
|
||||
ExcelExportAction_getXLSXPath_directory=DataSourceSummary
|
||||
ExcelExportAction_moduleName=Data Source Summary
|
||||
ExcelExportAction_runXLSXExport_errorMessage=There was an error while exporting.
|
||||
ExcelExportAction_runXLSXExport_errorTitle=Error While Exporting
|
||||
ExcelExportAction_runXLSXExport_progressCancelActionTitle=Cancelling...
|
||||
ExcelExportAction_runXLSXExport_progressCancelTitle=Cancel
|
||||
# {0} - dataSource
|
||||
ExcelExportAction_runXLSXExport_progressTitle=Exporting {0} to XLSX
|
||||
ExcelExportDialog_title=Data Source Summary Exported
|
||||
DataSourceUserActivitySummary_getRecentAccounts_calllogMessage=Call Log
|
||||
DataSourceUserActivitySummary_getRecentAccounts_emailMessage=Email Message
|
||||
GeolocationPanel_cityColumn_title=Closest City
|
||||
GeolocationPanel_countColumn_title=Count
|
||||
GeolocationPanel_mostCommon_tabName=Most Common Cities
|
||||
GeolocationPanel_mostRecent_tabName=Most Recent Cities
|
||||
GeolocationPanel_onNoCrIngest_message=No results will be shown because the GPX Parser was not run.
|
||||
GeolocationPanel_unknownRow_title=Unknown
|
||||
IngestJobExcelExport_endTimeColumn=End Time
|
||||
IngestJobExcelExport_ingestStatusTimeColumn=Ingest Status
|
||||
IngestJobExcelExport_moduleNameTimeColumn=Module Name
|
||||
IngestJobExcelExport_sheetName=Ingest History
|
||||
IngestJobExcelExport_startTimeColumn=Start Time
|
||||
IngestJobExcelExport_versionColumn=Module Version
|
||||
PastCasesPanel_caseColumn_title=Case
|
||||
PastCasesPanel_countColumn_title=Count
|
||||
PastCasesPanel_notableFileTable_tabName=Cases with Common Notable
|
||||
PastCasesPanel_onNoCrIngest_message=No results will be shown because the Central Repository module was not run.
|
||||
PastCasesPanel_sameIdsTable_tabName=Past Cases with the Same Devices
|
||||
RecentFilePanel_col_header_domain=Domain
|
||||
RecentFilePanel_col_header_path=Path
|
||||
RecentFilePanel_col_header_sender=Sender
|
||||
RecentFilePanel_emailParserModuleName=Email Parser
|
||||
RecentFilePanel_no_open_documents=No recently open documents found.
|
||||
RecentFilesPanel_attachmentsTable_tabName=Recent Attachments
|
||||
RecentFilesPanel_col_head_date=Date
|
||||
RecentFilesPanel_col_header_domain=Domain
|
||||
RecentFilesPanel_col_header_path=Path
|
||||
RecentFilesPanel_col_header_sender=Sender
|
||||
RecentFilesPanel_docsTable_tabName=Recently Opened Documents
|
||||
RecentFilesPanel_downloadsTable_tabName=Recently Downloads
|
||||
RecentFilesPanel_no_open_documents=No recently open documents found.
|
||||
SizeRepresentationUtil_units_bytes=bytes
|
||||
SizeRepresentationUtil_units_gigabytes=GB
|
||||
SizeRepresentationUtil_units_kilobytes=KB
|
||||
@ -116,12 +84,6 @@ SizeRepresentationUtil_units_megabytes=MB
|
||||
SizeRepresentationUtil_units_petabytes=PB
|
||||
SizeRepresentationUtil_units_terabytes=TB
|
||||
TimelinePanel_earliestLabel_title=Earliest
|
||||
TimelinePanel_getExports_activityRange=Activity Range
|
||||
TimelinePanel_getExports_chartName=Last 30 Days
|
||||
TimelinePanel_getExports_dateColumnHeader=Date
|
||||
TimelinePanel_getExports_earliest=Earliest:
|
||||
TimelinePanel_getExports_latest=Latest:
|
||||
TimelinePanel_getExports_sheetName=Timeline
|
||||
TimelinePanel_latestLabel_title=Latest
|
||||
TimlinePanel_last30DaysChart_artifactEvts_title=Result Events
|
||||
TimlinePanel_last30DaysChart_fileEvts_title=File Events
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2019 Basis Technology Corp.
|
||||
* Copyright 2019-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -19,39 +19,23 @@
|
||||
package org.sleuthkit.autopsy.datasourcesummary.ui;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import javax.swing.table.DefaultTableModel;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
|
||||
import static org.sleuthkit.autopsy.datasourcesummary.ui.BaseDataSourceSummaryPanel.getFetchResult;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary.ContainerDetails;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary.ImageDetails;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult.ResultType;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultUpdateGovernor;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelSheetExport;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.ExcelItemExportable;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.KeyValueItemExportable;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.SingleCellExportable;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.TitledExportable;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.UpdateGovernor;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import org.sleuthkit.datamodel.Image;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Panel to display additional details associated with a specific DataSource
|
||||
@ -61,182 +45,6 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
})
|
||||
class ContainerPanel extends BaseDataSourceSummaryPanel {
|
||||
|
||||
/**
|
||||
* View model data for data source images.
|
||||
*/
|
||||
private static class ImageViewModel {
|
||||
|
||||
private final long unallocatedSize;
|
||||
private final long size;
|
||||
private final long sectorSize;
|
||||
|
||||
private final String timeZone;
|
||||
private final String imageType;
|
||||
|
||||
private final List<String> paths;
|
||||
private final String md5Hash;
|
||||
private final String sha1Hash;
|
||||
private final String sha256Hash;
|
||||
|
||||
/**
|
||||
* Main constructor.
|
||||
*
|
||||
* @param unallocatedSize Size in bytes of unallocated space.
|
||||
* @param size Total size in bytes.
|
||||
* @param sectorSize Sector size in bytes.
|
||||
* @param timeZone The time zone.
|
||||
* @param imageType The type of image.
|
||||
* @param paths The source paths for the image.
|
||||
* @param md5Hash The md5 hash or null.
|
||||
* @param sha1Hash The sha1 hash or null.
|
||||
* @param sha256Hash The sha256 hash or null.
|
||||
*/
|
||||
ImageViewModel(long unallocatedSize, long size, long sectorSize,
|
||||
String timeZone, String imageType, List<String> paths, String md5Hash,
|
||||
String sha1Hash, String sha256Hash) {
|
||||
this.unallocatedSize = unallocatedSize;
|
||||
this.size = size;
|
||||
this.sectorSize = sectorSize;
|
||||
this.timeZone = timeZone;
|
||||
this.imageType = imageType;
|
||||
this.paths = paths == null ? Collections.emptyList() : new ArrayList<>(paths);
|
||||
this.md5Hash = md5Hash;
|
||||
this.sha1Hash = sha1Hash;
|
||||
this.sha256Hash = sha256Hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Size in bytes of unallocated space.
|
||||
*/
|
||||
long getUnallocatedSize() {
|
||||
return unallocatedSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Total size in bytes.
|
||||
*/
|
||||
long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Sector size in bytes.
|
||||
*/
|
||||
long getSectorSize() {
|
||||
return sectorSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The time zone.
|
||||
*/
|
||||
String getTimeZone() {
|
||||
return timeZone;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The type of image.
|
||||
*/
|
||||
String getImageType() {
|
||||
return imageType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The source paths for the image.
|
||||
*/
|
||||
List<String> getPaths() {
|
||||
return paths;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The md5 hash or null.
|
||||
*/
|
||||
String getMd5Hash() {
|
||||
return md5Hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The sha1 hash or null.
|
||||
*/
|
||||
String getSha1Hash() {
|
||||
return sha1Hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The sha256 hash or null.
|
||||
*/
|
||||
String getSha256Hash() {
|
||||
return sha256Hash;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* View model for container data.
|
||||
*/
|
||||
private static class ContainerViewModel {
|
||||
|
||||
private final String displayName;
|
||||
private final String originalName;
|
||||
private final String deviceIdValue;
|
||||
private final String acquisitionDetails;
|
||||
private final ImageViewModel imageViewModel;
|
||||
|
||||
/**
|
||||
* Main constructor.
|
||||
*
|
||||
* @param displayName The display name for this data source.
|
||||
* @param originalName The original name for this data source.
|
||||
* @param deviceIdValue The device id value for this data source.
|
||||
* @param acquisitionDetails The acquisition details for this data
|
||||
* source or null.
|
||||
* @param imageViewModel If the data source is an image, the image view
|
||||
* model for this data source or null if non-image.
|
||||
*/
|
||||
ContainerViewModel(String displayName, String originalName, String deviceIdValue,
|
||||
String acquisitionDetails, ImageViewModel imageViewModel) {
|
||||
this.displayName = displayName;
|
||||
this.originalName = originalName;
|
||||
this.deviceIdValue = deviceIdValue;
|
||||
this.acquisitionDetails = acquisitionDetails;
|
||||
this.imageViewModel = imageViewModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The display name for this data source.
|
||||
*/
|
||||
String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The original name for this data source.
|
||||
*/
|
||||
String getOriginalName() {
|
||||
return originalName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The device id value for this data source.
|
||||
*/
|
||||
String getDeviceId() {
|
||||
return deviceIdValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The acquisition details for this data source or null.
|
||||
*/
|
||||
String getAcquisitionDetails() {
|
||||
return acquisitionDetails;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return If the data source is an image, the image view model for this
|
||||
* data source or null if non-image.
|
||||
*/
|
||||
ImageViewModel getImageViewModel() {
|
||||
return imageViewModel;
|
||||
}
|
||||
}
|
||||
|
||||
// set of case events for which to call update (if the name changes, that will impact data shown)
|
||||
private static final Set<Case.Events> CASE_EVENT_SET = new HashSet<>(Arrays.asList(
|
||||
Case.Events.DATA_SOURCE_NAME_CHANGED
|
||||
@ -262,29 +70,29 @@ class ContainerPanel extends BaseDataSourceSummaryPanel {
|
||||
private static final Logger logger = Logger.getLogger(ContainerPanel.class.getName());
|
||||
|
||||
private final List<DataFetchComponents<DataSource, ?>> dataFetchComponents;
|
||||
private final DataFetcher<DataSource, ContainerViewModel> containerDataFetcher;
|
||||
private final DataFetcher<DataSource, ContainerDetails> containerDataFetcher;
|
||||
|
||||
/**
|
||||
* Creates a new form ContainerPanel.
|
||||
*/
|
||||
ContainerPanel() {
|
||||
this(new ContainerSummary());
|
||||
this(new ContainerSummaryGetter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new form ContainerPanel.
|
||||
*/
|
||||
ContainerPanel(ContainerSummary containerSummary) {
|
||||
ContainerPanel(ContainerSummaryGetter containerSummary) {
|
||||
super(containerSummary, CONTAINER_UPDATES);
|
||||
|
||||
containerDataFetcher = (dataSource) -> getContainerViewModel(containerSummary, dataSource);
|
||||
containerDataFetcher = (dataSource) -> containerSummary.getContainerDetails(dataSource);
|
||||
|
||||
dataFetchComponents = Arrays.asList(
|
||||
new DataFetchComponents<>(
|
||||
containerDataFetcher,
|
||||
(result) -> {
|
||||
if (result != null && result.getResultType() == ResultType.SUCCESS) {
|
||||
ContainerViewModel data = result.getData();
|
||||
ContainerDetails data = result.getData();
|
||||
updateDetailsPanelData(data);
|
||||
} else {
|
||||
if (result == null) {
|
||||
@ -313,92 +121,12 @@ class ContainerPanel extends BaseDataSourceSummaryPanel {
|
||||
fetchInformation(dataFetchComponents, dataSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* A means of retrieving data that could potentially throw an exception.
|
||||
*/
|
||||
private interface Retriever<O> {
|
||||
|
||||
/**
|
||||
* Retrieves data of a certain type and possibly throws an exception.
|
||||
*
|
||||
* @return The data type.
|
||||
* @throws TskCoreException
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws SQLException
|
||||
*/
|
||||
O retrieve() throws TskCoreException, SleuthkitCaseProviderException, SQLException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves data of a particular type and handles any exceptions that may
|
||||
* be thrown by logging.
|
||||
*
|
||||
* @param retriever The retrieving function.
|
||||
* @return The retrieved data.
|
||||
*/
|
||||
private static <O> O retrieve(Retriever<O> retriever) {
|
||||
try {
|
||||
return retriever.retrieve();
|
||||
} catch (TskCoreException | SleuthkitCaseProviderException | SQLException ex) {
|
||||
logger.log(Level.WARNING, "Error while retrieving data.", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a container view model object containing data to display about
|
||||
* the data source.
|
||||
*
|
||||
* @param containerSummary The service providing data about the data source.
|
||||
* @param ds The data source.
|
||||
* @return The generated view model.
|
||||
*/
|
||||
private static ContainerViewModel getContainerViewModel(ContainerSummary containerSummary, DataSource ds) {
|
||||
if (ds == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ContainerViewModel(
|
||||
ds.getName(),
|
||||
ds.getName(),
|
||||
ds.getDeviceId(),
|
||||
retrieve(() -> ds.getAcquisitionDetails()),
|
||||
ds instanceof Image ? getImageViewModel(containerSummary, (Image) ds) : null
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an image view model object containing data to display about the
|
||||
* image.
|
||||
*
|
||||
* @param containerSummary The service providing data about the image.
|
||||
* @param image The image.
|
||||
* @return The generated view model.
|
||||
*/
|
||||
private static ImageViewModel getImageViewModel(ContainerSummary containerSummary, Image image) {
|
||||
if (image == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Long unallocSize = retrieve(() -> containerSummary.getSizeOfUnallocatedFiles(image));
|
||||
String imageType = image.getType().getName();
|
||||
Long size = image.getSize();
|
||||
Long sectorSize = image.getSsize();
|
||||
String timeZone = image.getTimeZone();
|
||||
List<String> paths = image.getPaths() == null ? Collections.emptyList() : Arrays.asList(image.getPaths());
|
||||
String md5 = retrieve(() -> image.getMd5());
|
||||
String sha1 = retrieve(() -> image.getSha1());
|
||||
String sha256 = retrieve(() -> image.getSha256());
|
||||
|
||||
return new ImageViewModel(unallocSize, size, sectorSize, timeZone, imageType, paths, md5, sha1, sha256);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the swing components with fetched data.
|
||||
*
|
||||
* @param viewModel The data source view model data.
|
||||
*/
|
||||
private void updateDetailsPanelData(ContainerViewModel viewModel) {
|
||||
private void updateDetailsPanelData(ContainerDetails viewModel) {
|
||||
clearTableValues();
|
||||
if (viewModel == null) {
|
||||
return;
|
||||
@ -409,8 +137,8 @@ class ContainerPanel extends BaseDataSourceSummaryPanel {
|
||||
deviceIdValue.setText(viewModel.getDeviceId());
|
||||
acquisitionDetailsTextArea.setText(viewModel.getAcquisitionDetails());
|
||||
|
||||
if (viewModel.getImageViewModel() != null) {
|
||||
setFieldsForImage(viewModel.getImageViewModel());
|
||||
if (viewModel.getImageDetails() != null) {
|
||||
setFieldsForImage(viewModel.getImageDetails());
|
||||
} else {
|
||||
setFieldsForNonImageDataSource();
|
||||
}
|
||||
@ -445,7 +173,7 @@ class ContainerPanel extends BaseDataSourceSummaryPanel {
|
||||
*
|
||||
* @param viewModel The image view model data.
|
||||
*/
|
||||
private void setFieldsForImage(ImageViewModel viewModel) {
|
||||
private void setFieldsForImage(ImageDetails viewModel) {
|
||||
unallocatedSizeValue.setText(SizeRepresentationUtil.getSizeString(viewModel.getUnallocatedSize()));
|
||||
imageTypeValue.setText(viewModel.getImageType());
|
||||
sizeValue.setText(SizeRepresentationUtil.getSizeString(viewModel.getSize()));
|
||||
@ -480,84 +208,6 @@ class ContainerPanel extends BaseDataSourceSummaryPanel {
|
||||
((DefaultTableModel) filePathsTable.getModel()).setRowCount(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Divides acquisition details into key/value pairs to be displayed in
|
||||
* separate cells in an excel export.
|
||||
*
|
||||
* @param acquisitionDetails The acquisition details.
|
||||
* @return The list of key value pairs that can be incorporated into the
|
||||
* excel export.
|
||||
*/
|
||||
private static List<? extends ExcelItemExportable> getAcquisitionDetails(String acquisitionDetails) {
|
||||
if (StringUtils.isBlank(acquisitionDetails)) {
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
return Stream.of(acquisitionDetails.split("\\r?\\n"))
|
||||
.map((line) -> (StringUtils.isBlank(line)) ? null : new SingleCellExportable(line))
|
||||
.filter(item -> item != null)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Messages({
|
||||
"ContainerPanel_export_displayName=Display Name:",
|
||||
"ContainerPanel_export_originalName=Name:",
|
||||
"ContainerPanel_export_deviceId=Device ID:",
|
||||
"ContainerPanel_export_timeZone=Time Zone:",
|
||||
"ContainerPanel_export_acquisitionDetails=Acquisition Details:",
|
||||
"ContainerPanel_export_imageType=Image Type:",
|
||||
"ContainerPanel_export_size=Size:",
|
||||
"ContainerPanel_export_sectorSize=Sector Size:",
|
||||
"ContainerPanel_export_md5=MD5:",
|
||||
"ContainerPanel_export_sha1=SHA1:",
|
||||
"ContainerPanel_export_sha256=SHA256:",
|
||||
"ContainerPanel_export_unallocatedSize=Unallocated Space:",
|
||||
"ContainerPanel_export_filePaths=File Paths:",})
|
||||
protected List<ExcelSheetExport> getExports(DataSource ds) {
|
||||
ContainerViewModel result = getFetchResult(containerDataFetcher, "Container sheets", ds);
|
||||
if (ds == null || result == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
String NA = Bundle.ContainerPanel_setFieldsForNonImageDataSource_na();
|
||||
DefaultCellModel<?> NACell = new DefaultCellModel<>(NA);
|
||||
|
||||
ImageViewModel imageModel = result.getImageViewModel();
|
||||
boolean hasImage = imageModel != null;
|
||||
|
||||
DefaultCellModel<?> timeZone = hasImage ? new DefaultCellModel<>(imageModel.getTimeZone()) : NACell;
|
||||
DefaultCellModel<?> imageType = hasImage ? new DefaultCellModel<>(imageModel.getImageType()) : NACell;
|
||||
DefaultCellModel<?> size = hasImage ? SizeRepresentationUtil.getBytesCell(imageModel.getSize()) : NACell;
|
||||
DefaultCellModel<?> sectorSize = hasImage ? SizeRepresentationUtil.getBytesCell(imageModel.getSectorSize()) : NACell;
|
||||
DefaultCellModel<?> md5 = hasImage ? new DefaultCellModel<>(imageModel.getMd5Hash()) : NACell;
|
||||
DefaultCellModel<?> sha1 = hasImage ? new DefaultCellModel<>(imageModel.getSha1Hash()) : NACell;
|
||||
DefaultCellModel<?> sha256 = hasImage ? new DefaultCellModel<>(imageModel.getSha256Hash()) : NACell;
|
||||
DefaultCellModel<?> unallocatedSize = hasImage ? SizeRepresentationUtil.getBytesCell(imageModel.getUnallocatedSize()) : NACell;
|
||||
List<String> paths = result.getImageViewModel() == null ? Collections.singletonList(NA) : result.getImageViewModel().getPaths();
|
||||
List<SingleCellExportable> cellPaths = paths.stream()
|
||||
.map(SingleCellExportable::new)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return Arrays.asList(
|
||||
new ExcelSpecialFormatExport(Bundle.ContainerPanel_tabName(), Arrays.asList(
|
||||
new KeyValueItemExportable(Bundle.ContainerPanel_export_displayName(), new DefaultCellModel<>(result.getDisplayName())),
|
||||
new KeyValueItemExportable(Bundle.ContainerPanel_export_originalName(), new DefaultCellModel<>(result.getOriginalName())),
|
||||
new KeyValueItemExportable(Bundle.ContainerPanel_export_deviceId(), new DefaultCellModel<>(result.getDeviceId())),
|
||||
new KeyValueItemExportable(Bundle.ContainerPanel_export_timeZone(), timeZone),
|
||||
new TitledExportable(Bundle.ContainerPanel_export_acquisitionDetails(), getAcquisitionDetails(result.getAcquisitionDetails())),
|
||||
new KeyValueItemExportable(Bundle.ContainerPanel_export_imageType(), imageType),
|
||||
new KeyValueItemExportable(Bundle.ContainerPanel_export_size(), size),
|
||||
new KeyValueItemExportable(Bundle.ContainerPanel_export_sectorSize(), sectorSize),
|
||||
new KeyValueItemExportable(Bundle.ContainerPanel_export_md5(), md5),
|
||||
new KeyValueItemExportable(Bundle.ContainerPanel_export_sha1(), sha1),
|
||||
new KeyValueItemExportable(Bundle.ContainerPanel_export_sha256(), sha256),
|
||||
new KeyValueItemExportable(Bundle.ContainerPanel_export_unallocatedSize(), unallocatedSize),
|
||||
new TitledExportable(Bundle.ContainerPanel_export_filePaths(), cellPaths)
|
||||
)));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020-2021 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.datasourcesummary.ui;
|
||||
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary;
|
||||
import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Wrapper class for converting
|
||||
* org.sleuthkit.autopsy.contentutils.ContainerSummary functionality into a
|
||||
* DefaultArtifactUpdateGovernor used by Container tab.
|
||||
*/
|
||||
public class ContainerSummaryGetter implements DefaultArtifactUpdateGovernor {
|
||||
|
||||
private static final Set<Integer> ARTIFACT_UPDATE_TYPE_IDS = new HashSet<>(Arrays.asList(
|
||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_OS_INFO.getTypeID(),
|
||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_DATA_SOURCE_USAGE.getTypeID()
|
||||
));
|
||||
|
||||
private final ContainerSummary containerSummary;
|
||||
|
||||
/**
|
||||
* Main constructor.
|
||||
*/
|
||||
public ContainerSummaryGetter() {
|
||||
containerSummary = new ContainerSummary();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshRequired(ModuleContentEvent evt) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshRequired(AbstractFile file) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Integer> getArtifactTypeIdsForRefresh() {
|
||||
return Collections.unmodifiableSet(ARTIFACT_UPDATE_TYPE_IDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size of unallocated files in a particular datasource.
|
||||
*
|
||||
* @param currentDataSource The data source.
|
||||
*
|
||||
* @return The size or null if the query could not be executed.
|
||||
*
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
* @throws SQLException
|
||||
*/
|
||||
public Long getSizeOfUnallocatedFiles(DataSource currentDataSource)
|
||||
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
|
||||
return containerSummary.getSizeOfUnallocatedFiles(currentDataSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the concatenation of operating system attributes for a
|
||||
* particular data source.
|
||||
*
|
||||
* @param dataSource The data source.
|
||||
*
|
||||
* @return The concatenated value or null if the query could not be
|
||||
* executed.
|
||||
*
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
* @throws SQLException
|
||||
*/
|
||||
public String getOperatingSystems(DataSource dataSource)
|
||||
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
|
||||
return containerSummary.getOperatingSystems(dataSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the concatenation of data source usage for a particular data
|
||||
* source.
|
||||
*
|
||||
* @param dataSource The data source.
|
||||
*
|
||||
* @return The concatenated value or null if the query could not be
|
||||
* executed.
|
||||
*
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
* @throws SQLException
|
||||
*/
|
||||
public String getDataSourceType(DataSource dataSource)
|
||||
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
|
||||
return containerSummary.getDataSourceType(dataSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a container data model object containing data about the data
|
||||
* source.
|
||||
*
|
||||
* @param dataSource The data source.
|
||||
*
|
||||
* @return The concatenated value or null if the query could not be
|
||||
* executed.
|
||||
*
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
* @throws SQLException
|
||||
*/
|
||||
public ContainerSummary.ContainerDetails getContainerDetails(DataSource dataSource)
|
||||
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
|
||||
return containerSummary.getContainerDetails(dataSource);
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datasourcesummary.ui;
|
||||
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.CaseDataSourcesSummary;
|
||||
import java.awt.Cursor;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.RightAlignedTableCellRenderer;
|
||||
import java.awt.EventQueue;
|
||||
@ -42,7 +43,6 @@ import static javax.swing.SwingConstants.RIGHT;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.SwingWorker;
|
||||
import javax.swing.table.TableColumn;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.CaseDataSourcesSummary;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import org.sleuthkit.datamodel.IngestJobInfo;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
|
@ -25,12 +25,9 @@ import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.IngestJobInfoPanel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.ui.ExcelExportAction.ExportableTab;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelSheetExport;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
|
||||
/**
|
||||
@ -46,8 +43,7 @@ import org.sleuthkit.datamodel.DataSource;
|
||||
"DataSourceSummaryTabbedPane_pastCasesTab_title=Past Cases",
|
||||
"DataSourceSummaryTabbedPane_analysisTab_title=Analysis",
|
||||
"DataSourceSummaryTabbedPane_geolocationTab_title=Geolocation",
|
||||
"DataSourceSummaryTabbedPane_timelineTab_title=Timeline",
|
||||
"DataSourceSummaryTabbedPane_exportTab_title=Export"
|
||||
"DataSourceSummaryTabbedPane_timelineTab_title=Timeline"
|
||||
})
|
||||
public class DataSourceSummaryTabbedPane extends javax.swing.JPanel {
|
||||
|
||||
@ -55,12 +51,11 @@ public class DataSourceSummaryTabbedPane extends javax.swing.JPanel {
|
||||
* Records of tab information (i.e. title, component, function to call on
|
||||
* new data source).
|
||||
*/
|
||||
private class DataSourceTab implements ExportableTab {
|
||||
private class DataSourceTab {
|
||||
|
||||
private final String tabTitle;
|
||||
private final Component component;
|
||||
private final Consumer<DataSource> onDataSource;
|
||||
private final Function<DataSource, List<ExcelSheetExport>> excelExporter;
|
||||
private final Runnable onClose;
|
||||
private final Runnable onInit;
|
||||
|
||||
@ -71,7 +66,7 @@ public class DataSourceSummaryTabbedPane extends javax.swing.JPanel {
|
||||
* @param panel The component to be displayed in the tab.
|
||||
*/
|
||||
DataSourceTab(String tabTitle, BaseDataSourceSummaryPanel panel) {
|
||||
this(tabTitle, panel, panel::setDataSource, panel::getExports, panel::close, panel::init);
|
||||
this(tabTitle, panel, panel::setDataSource, panel::close, panel::init);
|
||||
panel.setParentCloseListener(() -> notifyParentClose());
|
||||
}
|
||||
|
||||
@ -90,12 +85,10 @@ public class DataSourceSummaryTabbedPane extends javax.swing.JPanel {
|
||||
* added to the tabbed pane.
|
||||
*/
|
||||
DataSourceTab(String tabTitle, Component component, Consumer<DataSource> onDataSource,
|
||||
Function<DataSource, List<ExcelSheetExport>> excelExporter, Runnable onClose,
|
||||
Runnable onInit) {
|
||||
Runnable onClose, Runnable onInit) {
|
||||
this.tabTitle = tabTitle;
|
||||
this.component = component;
|
||||
this.onDataSource = onDataSource;
|
||||
this.excelExporter = excelExporter;
|
||||
this.onClose = onClose;
|
||||
this.onInit = onInit;
|
||||
}
|
||||
@ -103,7 +96,6 @@ public class DataSourceSummaryTabbedPane extends javax.swing.JPanel {
|
||||
/**
|
||||
* @return The title for the tab.
|
||||
*/
|
||||
@Override
|
||||
public String getTabTitle() {
|
||||
return tabTitle;
|
||||
}
|
||||
@ -122,11 +114,6 @@ public class DataSourceSummaryTabbedPane extends javax.swing.JPanel {
|
||||
return onDataSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ExcelSheetExport> getExcelExports(DataSource dataSource) {
|
||||
return excelExporter == null ? null : excelExporter.apply(dataSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The action for closing resources in the tab.
|
||||
*/
|
||||
@ -152,9 +139,6 @@ public class DataSourceSummaryTabbedPane extends javax.swing.JPanel {
|
||||
private Runnable notifyParentClose = null;
|
||||
private final IngestJobInfoPanel ingestHistoryPanel = new IngestJobInfoPanel();
|
||||
|
||||
// create an export panel whose button triggers the export to XLSX action
|
||||
private final ExportPanel exportPanel = new ExportPanel();
|
||||
|
||||
private final List<DataSourceTab> tabs = Arrays.asList(
|
||||
new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_typesTab_title(), new TypesPanel()),
|
||||
new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_userActivityTab_title(), new UserActivityPanel()),
|
||||
@ -168,22 +152,11 @@ public class DataSourceSummaryTabbedPane extends javax.swing.JPanel {
|
||||
Bundle.DataSourceSummaryTabbedPane_ingestHistoryTab_title(),
|
||||
ingestHistoryPanel,
|
||||
ingestHistoryPanel::setDataSource,
|
||||
IngestJobExcelExport::getExports,
|
||||
null,
|
||||
null),
|
||||
new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_detailsTab_title(), new ContainerPanel()),
|
||||
new DataSourceTab(
|
||||
Bundle.DataSourceSummaryTabbedPane_exportTab_title(),
|
||||
exportPanel,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null)
|
||||
new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_detailsTab_title(), new ContainerPanel())
|
||||
);
|
||||
|
||||
// the action that does the export
|
||||
private final ExcelExportAction exportAction = new ExcelExportAction(tabs);
|
||||
|
||||
private DataSource dataSource = null;
|
||||
private CardLayout cardLayout;
|
||||
|
||||
@ -243,9 +216,6 @@ public class DataSourceSummaryTabbedPane extends javax.swing.JPanel {
|
||||
|
||||
// set this to no datasource initially
|
||||
cardLayout.show(this, NO_DATASOURCE_PANE);
|
||||
|
||||
// set action for when user requests xlsx export
|
||||
exportPanel.setXlsxExportAction(() -> exportAction.accept(getDataSource()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,301 +0,0 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2021 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.datasourcesummary.ui;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.SwingWorker;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.openide.windows.WindowManager;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.coreutils.FileUtil;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelExportException;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelSheetExport;
|
||||
import org.sleuthkit.autopsy.progress.ModalDialogProgressIndicator;
|
||||
import org.sleuthkit.autopsy.progress.ProgressIndicator;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Action that exports tab data to an excel workbook.
|
||||
*/
|
||||
@Messages({
|
||||
"ExcelExportAction_moduleName=Data Source Summary",})
|
||||
class ExcelExportAction implements Consumer<DataSource> {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ExcelExportAction.class.getName());
|
||||
|
||||
/**
|
||||
* A tab that can be exported.
|
||||
*/
|
||||
interface ExportableTab {
|
||||
|
||||
/**
|
||||
* Returns the name of the tab.
|
||||
*
|
||||
* @return The tab name.
|
||||
*/
|
||||
String getTabTitle();
|
||||
|
||||
/**
|
||||
* Given the data source, provides the excel exports for this tab.
|
||||
*
|
||||
* @param dataSource The data source.
|
||||
* @return The excel exports or null.
|
||||
*/
|
||||
List<ExcelSheetExport> getExcelExports(DataSource dataSource);
|
||||
}
|
||||
|
||||
private final ExcelExport excelExport = ExcelExport.getInstance();
|
||||
private final List<? extends ExportableTab> tabExports;
|
||||
|
||||
/**
|
||||
* Main constructor.
|
||||
*
|
||||
* @param tabExports The different tabs that may have excel exports.
|
||||
*/
|
||||
ExcelExportAction(List<? extends ExportableTab> tabExports) {
|
||||
this.tabExports = Collections.unmodifiableList(new ArrayList<>(tabExports));
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts the data source for which this export pertains, prompts user for
|
||||
* output location, and exports the data.
|
||||
*
|
||||
* @param ds The data source.
|
||||
*/
|
||||
@Override
|
||||
public void accept(DataSource ds) {
|
||||
if (ds == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
File outputLoc = getXLSXPath(ds.getName());
|
||||
if (outputLoc == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
runXLSXExport(ds, outputLoc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an xlsx path for the data source summary export.
|
||||
*
|
||||
* @param dataSourceName The name of the data source.
|
||||
* @return The file to which the excel document should be written or null if
|
||||
* file already exists or cancellation.
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"ExcelExportAction_getXLSXPath_directory=DataSourceSummary",})
|
||||
private File getXLSXPath(String dataSourceName) {
|
||||
// set initial path to reports directory with filename that is
|
||||
// a combination of the data source name and time stamp
|
||||
DateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy-HH-mm-ss");
|
||||
String fileName = String.format("%s-%s.xlsx", dataSourceName == null ? "" : FileUtil.escapeFileName(dataSourceName), dateFormat.format(new Date()));
|
||||
try {
|
||||
String reportsDir = Case.getCurrentCaseThrows().getReportDirectory();
|
||||
File reportsDirFile = Paths.get(reportsDir, Bundle.ExcelExportAction_getXLSXPath_directory()).toFile();
|
||||
if (!reportsDirFile.exists()) {
|
||||
reportsDirFile.mkdirs();
|
||||
}
|
||||
|
||||
return Paths.get(reportsDirFile.getAbsolutePath(), fileName).toFile();
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
logger.log(Level.WARNING, "Unable to find reports directory.", ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An action listener that handles cancellation of the export process.
|
||||
*/
|
||||
private class CancelExportListener implements ActionListener {
|
||||
|
||||
private SwingWorker<Boolean, Void> worker = null;
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (worker != null && !worker.isCancelled() && !worker.isDone()) {
|
||||
worker.cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the swing worker that could be cancelled.
|
||||
*
|
||||
* @return The swing worker that could be cancelled.
|
||||
*/
|
||||
SwingWorker<Boolean, Void> getWorker() {
|
||||
return worker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the swing worker that could be cancelled.
|
||||
*
|
||||
* @param worker The swing worker that could be cancelled.
|
||||
*/
|
||||
void setWorker(SwingWorker<Boolean, Void> worker) {
|
||||
this.worker = worker;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles managing the gui and exporting data from the tabs into an excel
|
||||
* document.
|
||||
*
|
||||
* @param dataSource The data source.
|
||||
* @param path The output path.
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"# {0} - dataSource",
|
||||
"ExcelExportAction_runXLSXExport_progressTitle=Exporting {0} to XLSX",
|
||||
"ExcelExportAction_runXLSXExport_progressCancelTitle=Cancel",
|
||||
"ExcelExportAction_runXLSXExport_progressCancelActionTitle=Cancelling...",
|
||||
"ExcelExportAction_runXLSXExport_errorTitle=Error While Exporting",
|
||||
"ExcelExportAction_runXLSXExport_errorMessage=There was an error while exporting.",
|
||||
})
|
||||
private void runXLSXExport(DataSource dataSource, File path) {
|
||||
|
||||
CancelExportListener cancelButtonListener = new CancelExportListener();
|
||||
|
||||
ProgressIndicator progressIndicator = new ModalDialogProgressIndicator(
|
||||
WindowManager.getDefault().getMainWindow(),
|
||||
Bundle.ExcelExportAction_runXLSXExport_progressTitle(dataSource.getName()),
|
||||
new String[]{Bundle.ExcelExportAction_runXLSXExport_progressCancelTitle()},
|
||||
Bundle.ExcelExportAction_runXLSXExport_progressCancelTitle(),
|
||||
cancelButtonListener
|
||||
);
|
||||
|
||||
SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() {
|
||||
@Override
|
||||
protected Boolean doInBackground() throws Exception {
|
||||
exportToXLSX(progressIndicator, dataSource, path);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
try {
|
||||
get();
|
||||
} catch (ExecutionException ex) {
|
||||
logger.log(Level.WARNING, "Error while trying to export data source summary to xlsx.", ex);
|
||||
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
|
||||
Bundle.ExcelExportAction_runXLSXExport_errorMessage(),
|
||||
Bundle.ExcelExportAction_runXLSXExport_errorTitle(),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
} catch (InterruptedException | CancellationException ex) {
|
||||
// no op on cancellation
|
||||
} finally {
|
||||
progressIndicator.finish();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cancelButtonListener.setWorker(worker);
|
||||
worker.execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Action that handles updating progress and exporting data from the tabs.
|
||||
*
|
||||
* @param progressIndicator The progress indicator.
|
||||
* @param dataSource The data source to be exported.
|
||||
* @param path The path of the excel export.
|
||||
* @throws InterruptedException
|
||||
* @throws IOException
|
||||
* @throws ExcelExportException
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"ExcelExportAction_exportToXLSX_beginExport=Beginning Export...",
|
||||
"# {0} - tabName",
|
||||
"ExcelExportAction_exportToXLSX_gatheringTabData=Fetching Data for {0} Tab...",
|
||||
"ExcelExportAction_exportToXLSX_writingToFile=Writing to File...",})
|
||||
|
||||
private void exportToXLSX(ProgressIndicator progressIndicator, DataSource dataSource, File path)
|
||||
throws InterruptedException, IOException, ExcelExport.ExcelExportException {
|
||||
|
||||
int exportWeight = 3;
|
||||
int totalWeight = tabExports.size() + exportWeight;
|
||||
progressIndicator.start(Bundle.ExcelExportAction_exportToXLSX_beginExport(), totalWeight);
|
||||
List<ExcelExport.ExcelSheetExport> sheetExports = new ArrayList<>();
|
||||
for (int i = 0; i < tabExports.size(); i++) {
|
||||
if (Thread.interrupted()) {
|
||||
throw new InterruptedException("Export has been cancelled.");
|
||||
}
|
||||
|
||||
ExportableTab tab = tabExports.get(i);
|
||||
progressIndicator.progress(Bundle.ExcelExportAction_exportToXLSX_gatheringTabData(tab == null ? "" : tab.getTabTitle()), i);
|
||||
|
||||
List<ExcelExport.ExcelSheetExport> exports = tab.getExcelExports(dataSource);
|
||||
if (exports != null) {
|
||||
sheetExports.addAll(exports);
|
||||
}
|
||||
}
|
||||
|
||||
if (Thread.interrupted()) {
|
||||
throw new InterruptedException("Export has been cancelled.");
|
||||
}
|
||||
|
||||
progressIndicator.progress(Bundle.ExcelExportAction_exportToXLSX_writingToFile(), tabExports.size());
|
||||
excelExport.writeExcel(sheetExports, path);
|
||||
|
||||
progressIndicator.finish();
|
||||
|
||||
try {
|
||||
// add to reports
|
||||
Case curCase = Case.getCurrentCaseThrows();
|
||||
curCase.addReport(path.getParent(),
|
||||
Bundle.ExcelExportAction_moduleName(),
|
||||
path.getName(),
|
||||
dataSource);
|
||||
|
||||
// and show finished dialog
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
ExcelExportDialog dialog = new ExcelExportDialog(WindowManager.getDefault().getMainWindow(), path);
|
||||
dialog.setResizable(false);
|
||||
dialog.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
|
||||
dialog.setVisible(true);
|
||||
dialog.toFront();
|
||||
});
|
||||
|
||||
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "There was an error attaching report to case.", ex);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,114 +0,0 @@
|
||||
<?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"/>
|
||||
</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="1" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="1" attributes="0">
|
||||
<Component id="linkTextScrollPane" max="32767" attributes="0"/>
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||
<Component id="okButton" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="titleLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="116" max="32767" 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"/>
|
||||
<Component id="titleLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="linkTextScrollPane" min="-2" pref="39" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="okButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="titleLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties" key="ExcelExportDialog.titleLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<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/datasourcesummary/ui/Bundle.properties" key="ExcelExportDialog.okButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="okButtonActionPerformed"/>
|
||||
</Events>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Container class="javax.swing.JScrollPane" name="linkTextScrollPane">
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
<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="linkText">
|
||||
<Properties>
|
||||
<Property name="editable" type="boolean" value="false"/>
|
||||
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||
<Color type="null"/>
|
||||
</Property>
|
||||
<Property name="columns" type="int" value="20"/>
|
||||
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||
<Connection code="java.awt.Color.BLUE" type="code"/>
|
||||
</Property>
|
||||
<Property name="lineWrap" type="boolean" value="true"/>
|
||||
<Property name="rows" type="int" value="1"/>
|
||||
<Property name="wrapStyleWord" type="boolean" value="true"/>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="null"/>
|
||||
</Property>
|
||||
<Property name="opaque" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Form>
|
@ -1,143 +0,0 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2021 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.datasourcesummary.ui;
|
||||
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Desktop;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.SwingUtilities;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
|
||||
/**
|
||||
* Dialog showing where the data source summary excel export can be located.
|
||||
*/
|
||||
@Messages({
|
||||
"ExcelExportDialog_title=Data Source Summary Exported"
|
||||
})
|
||||
public class ExcelExportDialog extends javax.swing.JDialog {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ExcelExportDialog.class.getName());
|
||||
|
||||
/**
|
||||
* Creates new form ExcelExportDialog
|
||||
*/
|
||||
public ExcelExportDialog(java.awt.Frame parent, File filePath) {
|
||||
super(parent, true);
|
||||
|
||||
initComponents();
|
||||
setTitle(Bundle.ExcelExportDialog_title());
|
||||
|
||||
this.linkText.setText(filePath.getAbsolutePath());
|
||||
this.linkText.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
try {
|
||||
Desktop.getDesktop().open(filePath);
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.WARNING, "Unable to open: " + filePath.getAbsolutePath(), ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
this.linkText.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
|
||||
javax.swing.JLabel titleLabel = new javax.swing.JLabel();
|
||||
javax.swing.JButton okButton = new javax.swing.JButton();
|
||||
javax.swing.JScrollPane linkTextScrollPane = new javax.swing.JScrollPane();
|
||||
linkText = new javax.swing.JTextArea();
|
||||
|
||||
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(titleLabel, org.openide.util.NbBundle.getMessage(ExcelExportDialog.class, "ExcelExportDialog.titleLabel.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(ExcelExportDialog.class, "ExcelExportDialog.okButton.text")); // NOI18N
|
||||
okButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
okButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
linkText.setEditable(false);
|
||||
linkText.setBackground(null);
|
||||
linkText.setColumns(20);
|
||||
linkText.setForeground(java.awt.Color.BLUE);
|
||||
linkText.setLineWrap(true);
|
||||
linkText.setRows(1);
|
||||
linkText.setWrapStyleWord(true);
|
||||
linkText.setBorder(null);
|
||||
linkText.setOpaque(false);
|
||||
linkTextScrollPane.setViewportView(linkText);
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
|
||||
getContentPane().setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addComponent(linkTextScrollPane)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(0, 0, Short.MAX_VALUE)
|
||||
.addComponent(okButton))
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
|
||||
.addComponent(titleLabel)
|
||||
.addGap(0, 116, Short.MAX_VALUE)))
|
||||
.addContainerGap())
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(titleLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(linkTextScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 39, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(okButton)
|
||||
.addContainerGap())
|
||||
);
|
||||
|
||||
pack();
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
|
||||
dispose();
|
||||
}//GEN-LAST:event_okButtonActionPerformed
|
||||
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JTextArea linkText;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<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" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="xlsxExportMessage" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="xlsxExportButton" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace pref="62" max="32767" 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"/>
|
||||
<Component id="xlsxExportMessage" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="xlsxExportButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="250" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JButton" name="xlsxExportButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties" key="ExportPanel.xlsxExportButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="xlsxExportButtonActionPerformed"/>
|
||||
</Events>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="xlsxExportMessage">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties" key="ExportPanel.xlsxExportMessage.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
@ -1,105 +0,0 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2021 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.datasourcesummary.ui;
|
||||
|
||||
/**
|
||||
* The panel that provides options for exporting data source summary data.
|
||||
*/
|
||||
public class ExportPanel extends javax.swing.JPanel {
|
||||
|
||||
private Runnable xlsxExportAction;
|
||||
|
||||
/**
|
||||
* Creates new form ExportPanel
|
||||
*/
|
||||
public ExportPanel() {
|
||||
initComponents();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the action that handles exporting to excel.
|
||||
*
|
||||
* @return The action that handles exporting to excel.
|
||||
*/
|
||||
public Runnable getXlsxExportAction() {
|
||||
return xlsxExportAction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the action that handles exporting to excel.
|
||||
*
|
||||
* @param onXlsxExport The action that handles exporting to excel.
|
||||
*/
|
||||
public void setXlsxExportAction(Runnable onXlsxExport) {
|
||||
this.xlsxExportAction = onXlsxExport;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
|
||||
javax.swing.JButton xlsxExportButton = new javax.swing.JButton();
|
||||
javax.swing.JLabel xlsxExportMessage = new javax.swing.JLabel();
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(xlsxExportButton, org.openide.util.NbBundle.getMessage(ExportPanel.class, "ExportPanel.xlsxExportButton.text")); // NOI18N
|
||||
xlsxExportButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
xlsxExportButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(xlsxExportMessage, org.openide.util.NbBundle.getMessage(ExportPanel.class, "ExportPanel.xlsxExportMessage.text")); // NOI18N
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(xlsxExportMessage)
|
||||
.addComponent(xlsxExportButton))
|
||||
.addContainerGap(62, Short.MAX_VALUE))
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(xlsxExportMessage)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(xlsxExportButton)
|
||||
.addContainerGap(250, Short.MAX_VALUE))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void xlsxExportButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_xlsxExportButtonActionPerformed
|
||||
if (this.xlsxExportAction != null) {
|
||||
xlsxExportAction.run();
|
||||
}
|
||||
}//GEN-LAST:event_xlsxExportButtonActionPerformed
|
||||
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
@ -34,7 +34,6 @@ import org.openide.util.NbBundle.Messages;
|
||||
import org.openide.util.actions.CallableSystemAction;
|
||||
import org.openide.windows.TopComponent;
|
||||
import org.openide.windows.WindowManager;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary.CityCountsList;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary.CityData;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary.CityRecordCount;
|
||||
@ -43,9 +42,8 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel;
|
||||
import org.sleuthkit.autopsy.geolocation.GeoFilter;
|
||||
@ -147,7 +145,7 @@ public class GeolocationPanel extends BaseDataSourceSummaryPanel {
|
||||
|
||||
private final IngestRunningLabel ingestRunningLabel = new IngestRunningLabel();
|
||||
|
||||
private final GeolocationSummary whereUsedData;
|
||||
private final GeolocationSummaryGetter whereUsedData;
|
||||
|
||||
private final DataFetcher<DataSource, GeolocationViewModel> geolocationFetcher;
|
||||
|
||||
@ -155,15 +153,15 @@ public class GeolocationPanel extends BaseDataSourceSummaryPanel {
|
||||
* Main constructor.
|
||||
*/
|
||||
public GeolocationPanel() {
|
||||
this(new GeolocationSummary());
|
||||
this(new GeolocationSummaryGetter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Main constructor.
|
||||
*
|
||||
* @param whereUsedData The GeolocationSummary instance to use.
|
||||
* @param whereUsedData The GeolocationSummaryGetter instance to use.
|
||||
*/
|
||||
public GeolocationPanel(GeolocationSummary whereUsedData) {
|
||||
public GeolocationPanel(GeolocationSummaryGetter whereUsedData) {
|
||||
super(whereUsedData);
|
||||
|
||||
this.whereUsedData = whereUsedData;
|
||||
@ -194,6 +192,7 @@ public class GeolocationPanel extends BaseDataSourceSummaryPanel {
|
||||
* Retrieves the city name to display from the record.
|
||||
*
|
||||
* @param record The record for the city to display.
|
||||
*
|
||||
* @return The display name (city, country).
|
||||
*/
|
||||
private static String getCityName(CityRecord record) {
|
||||
@ -221,6 +220,7 @@ public class GeolocationPanel extends BaseDataSourceSummaryPanel {
|
||||
* formats the city name).
|
||||
*
|
||||
* @param cityCount The CityRecordCount representing a row.
|
||||
*
|
||||
* @return The city/count pair to be displayed as a row.
|
||||
*/
|
||||
private Pair<String, Integer> formatRecord(CityRecordCount cityCount) {
|
||||
@ -240,6 +240,7 @@ public class GeolocationPanel extends BaseDataSourceSummaryPanel {
|
||||
*
|
||||
* @param countsList The CityCountsList object representing the data to be
|
||||
* displayed in the table.
|
||||
*
|
||||
* @return The list of city/count tuples to be displayed as a row.
|
||||
*/
|
||||
private List<Pair<String, Integer>> formatList(CityCountsList countsList) {
|
||||
@ -263,10 +264,11 @@ public class GeolocationPanel extends BaseDataSourceSummaryPanel {
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts CityData from GeolocationSummary into data that can be directly
|
||||
* put into table in this panel.
|
||||
* Converts CityData from GeolocationSummaryGetter into data that can be
|
||||
* directly put into table in this panel.
|
||||
*
|
||||
* @param cityData The city data.
|
||||
*
|
||||
* @return The view model data.
|
||||
*/
|
||||
private GeolocationViewModel convertToViewModel(CityData cityData) {
|
||||
@ -297,8 +299,8 @@ public class GeolocationPanel extends BaseDataSourceSummaryPanel {
|
||||
*
|
||||
* @param dataSource The data source for which the window should filter.
|
||||
* @param daysLimit The limit for how recently the waypoints should be (for
|
||||
* most recent table) or null for most recent filter to not be set (for most
|
||||
* common table).
|
||||
* most recent table) or null for most recent filter to
|
||||
* not be set (for most common table).
|
||||
*/
|
||||
private void openGeolocationWindow(DataSource dataSource, Integer daysLimit) {
|
||||
// notify dialog (if in dialog) should close.
|
||||
@ -349,19 +351,6 @@ public class GeolocationPanel extends BaseDataSourceSummaryPanel {
|
||||
onNewDataSource(dataFetchComponents, tables, dataSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
List<ExcelExport.ExcelSheetExport> getExports(DataSource dataSource) {
|
||||
GeolocationViewModel model = getFetchResult(geolocationFetcher, "Geolocation sheets", dataSource);
|
||||
if (model == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return Arrays.asList(
|
||||
getTableExport(DEFAULT_TEMPLATE, Bundle.GeolocationPanel_mostRecent_tabName(), model.getMostRecentData()),
|
||||
getTableExport(DEFAULT_TEMPLATE, Bundle.GeolocationPanel_mostCommon_tabName(), model.getMostCommonData())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
ingestRunningLabel.unregister();
|
||||
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020-2021 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.datasourcesummary.ui;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary.CityData;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor;
|
||||
import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationDataException;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
|
||||
/**
|
||||
* Wrapper class for converting
|
||||
* org.sleuthkit.autopsy.contentutils.GeolocationSummary functionality into a
|
||||
* DefaultArtifactUpdateGovernor used by GeolocationPanel tab.
|
||||
*/
|
||||
public class GeolocationSummaryGetter implements DefaultArtifactUpdateGovernor {
|
||||
|
||||
private final GeolocationSummary geoSummary;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public GeolocationSummaryGetter() {
|
||||
geoSummary = new GeolocationSummary();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns all the geolocation artifact types.
|
||||
*/
|
||||
public List<ARTIFACT_TYPE> getGeoTypes() {
|
||||
return GeolocationSummary.getGeoTypes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Integer> getArtifactTypeIdsForRefresh() {
|
||||
return GeolocationSummary.getArtifactTypeIdsForRefresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this list of hits per city where the list is sorted descending by
|
||||
* number of found hits (i.e. most hits is first index).
|
||||
*
|
||||
* @param dataSource The data source.
|
||||
* @param daysCount Number of days to go back.
|
||||
* @param maxCount Maximum number of results.
|
||||
*
|
||||
* @return The sorted list.
|
||||
*
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws GeoLocationDataException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public CityData getCityCounts(DataSource dataSource, int daysCount, int maxCount)
|
||||
throws SleuthkitCaseProviderException, GeoLocationDataException, InterruptedException, IOException {
|
||||
return geoSummary.getCityCounts(dataSource, daysCount, maxCount);
|
||||
}
|
||||
}
|
@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020-2021 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.datasourcesummary.ui;
|
||||
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultUpdateGovernor;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.MimeTypeSummary;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Wrapper class for converting org.sleuthkit.autopsy.contentutils.TypesSummary
|
||||
* functionality into a DefaultArtifactUpdateGovernor used by TypesPanel tab.
|
||||
*/
|
||||
public class MimeTypeSummaryGetter implements DefaultUpdateGovernor {
|
||||
|
||||
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS = new HashSet<>(
|
||||
Arrays.asList(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED));
|
||||
|
||||
private final MimeTypeSummary mimeTypeSummary;
|
||||
|
||||
/**
|
||||
* Main constructor.
|
||||
*/
|
||||
public MimeTypeSummaryGetter() {
|
||||
mimeTypeSummary = new MimeTypeSummary();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshRequired(ModuleContentEvent evt) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshRequired(AbstractFile file) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshRequired(IngestManager.IngestJobEvent evt) {
|
||||
return (evt != null && INGEST_JOB_EVENTS.contains(evt));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<IngestManager.IngestJobEvent> getIngestJobEventUpdates() {
|
||||
return Collections.unmodifiableSet(INGEST_JOB_EVENTS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of files in the case database for the current data source
|
||||
* which have the specified mimetypes.
|
||||
*
|
||||
* @param currentDataSource the data source which we are finding a file
|
||||
* count
|
||||
*
|
||||
* @param setOfMimeTypes the set of mime types which we are finding the
|
||||
* number of occurences of
|
||||
*
|
||||
* @return a Long value which represents the number of occurrences of the
|
||||
* specified mime types in the current case for the specified data
|
||||
* source, null if no count was retrieved
|
||||
*
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
* @throws SQLException
|
||||
*/
|
||||
public Long getCountOfFilesForMimeTypes(DataSource currentDataSource, Set<String> setOfMimeTypes)
|
||||
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
|
||||
return mimeTypeSummary.getCountOfFilesForMimeTypes(currentDataSource, setOfMimeTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of files in the case database for the current data source
|
||||
* which do not have the specified mimetypes.
|
||||
*
|
||||
* @param currentDataSource the data source which we are finding a file
|
||||
* count
|
||||
*
|
||||
* @param setOfMimeTypes the set of mime types that should be excluded.
|
||||
*
|
||||
* @return a Long value which represents the number of files that do not
|
||||
* have the specific mime type, but do have a mime type.
|
||||
*
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
* @throws SQLException
|
||||
*/
|
||||
public Long getCountOfFilesNotInMimeTypes(DataSource currentDataSource, Set<String> setOfMimeTypes)
|
||||
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
|
||||
return mimeTypeSummary.getCountOfFilesNotInMimeTypes(currentDataSource, setOfMimeTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a count of all regular files in a datasource.
|
||||
*
|
||||
* @param dataSource The datasource.
|
||||
*
|
||||
* @return The count of regular files.
|
||||
*
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
* @throws SQLException
|
||||
*/
|
||||
public Long getCountOfAllRegularFiles(DataSource dataSource)
|
||||
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
|
||||
return mimeTypeSummary.getCountOfAllRegularFiles(dataSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of files in the data source with no assigned mime type.
|
||||
*
|
||||
* @param currentDataSource The data source.
|
||||
*
|
||||
* @return The number of files with no mime type or null if there is an
|
||||
* issue searching the data source.
|
||||
*
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
* @throws SQLException
|
||||
*/
|
||||
public Long getCountOfFilesWithNoMimeType(DataSource currentDataSource)
|
||||
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
|
||||
return mimeTypeSummary.getCountOfFilesWithNoMimeType(currentDataSource);
|
||||
}
|
||||
}
|
@ -19,21 +19,16 @@
|
||||
package org.sleuthkit.autopsy.datasourcesummary.ui;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.PastCasesSummary;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.PastCasesSummary.PastCasesResult;
|
||||
import static org.sleuthkit.autopsy.datasourcesummary.ui.BaseDataSourceSummaryPanel.getFetchResult;
|
||||
import static org.sleuthkit.autopsy.datasourcesummary.ui.BaseDataSourceSummaryPanel.getTableExport;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
@ -86,13 +81,13 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel {
|
||||
private final DataFetcher<DataSource, PastCasesResult> pastCasesFetcher;
|
||||
|
||||
public PastCasesPanel() {
|
||||
this(new PastCasesSummary());
|
||||
this(new PastCasesSummaryGetter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new form PastCasesPanel
|
||||
*/
|
||||
public PastCasesPanel(PastCasesSummary pastCaseData) {
|
||||
public PastCasesPanel(PastCasesSummaryGetter pastCaseData) {
|
||||
super(pastCaseData);
|
||||
|
||||
this.pastCasesFetcher = (dataSource) -> pastCaseData.getPastCasesData(dataSource);
|
||||
@ -128,19 +123,6 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel {
|
||||
onNewDataSource(dataFetchComponents, tables, dataSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
List<ExcelExport.ExcelSheetExport> getExports(DataSource dataSource) {
|
||||
PastCasesResult result = getFetchResult(pastCasesFetcher, "Past cases sheets", dataSource);
|
||||
if (result == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return Arrays.asList(
|
||||
getTableExport(DEFAULT_TEMPLATE, Bundle.PastCasesPanel_notableFileTable_tabName(), result.getTaggedNotable()),
|
||||
getTableExport(DEFAULT_TEMPLATE, Bundle.PastCasesPanel_sameIdsTable_tabName(), result.getSameIdsResults())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
ingestRunningLabel.unregister();
|
||||
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2019 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.datasourcesummary.ui;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.PastCasesSummary;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.PastCasesSummary.PastCasesResult;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Wrapper class for converting
|
||||
* org.sleuthkit.autopsy.contentutils.PastCasesSummary functionality into a
|
||||
* DefaultArtifactUpdateGovernor used by PastCases tab.
|
||||
*/
|
||||
public class PastCasesSummaryGetter implements DefaultArtifactUpdateGovernor {
|
||||
|
||||
private static final Set<Integer> ARTIFACT_UPDATE_TYPE_IDS = new HashSet<>(Arrays.asList(
|
||||
ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(),
|
||||
ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()
|
||||
));
|
||||
|
||||
private final PastCasesSummary pastSummary;
|
||||
|
||||
public PastCasesSummaryGetter() {
|
||||
pastSummary = new PastCasesSummary();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Integer> getArtifactTypeIdsForRefresh() {
|
||||
return Collections.unmodifiableSet(ARTIFACT_UPDATE_TYPE_IDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the past cases data to be shown in the past cases tab.
|
||||
*
|
||||
* @param dataSource The data source.
|
||||
*
|
||||
* @return The retrieved data or null if null dataSource.
|
||||
*
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public PastCasesResult getPastCasesData(DataSource dataSource)
|
||||
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException {
|
||||
return pastSummary.getPastCasesData(dataSource);
|
||||
}
|
||||
}
|
116
Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesGetter.java
Executable file
116
Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesGetter.java
Executable file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020-2021 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.datasourcesummary.ui;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentAttachmentDetails;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentDownloadDetails;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentFileDetails;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
|
||||
/**
|
||||
* Wrapper class for converting
|
||||
* org.sleuthkit.autopsy.contentutils.RecentFilesSummary functionality into a
|
||||
* DefaultArtifactUpdateGovernor used by Recent Files Data Summary tab.
|
||||
*/
|
||||
public class RecentFilesGetter implements DefaultArtifactUpdateGovernor {
|
||||
|
||||
private static final Set<Integer> ARTIFACT_UPDATE_TYPE_IDS = new HashSet<>(Arrays.asList(
|
||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_RECENT_OBJECT.getTypeID(),
|
||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID(),
|
||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT.getTypeID(),
|
||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID(),
|
||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()
|
||||
));
|
||||
|
||||
private final RecentFilesSummary recentSummary;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public RecentFilesGetter() {
|
||||
recentSummary = new RecentFilesSummary();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Integer> getArtifactTypeIdsForRefresh() {
|
||||
return Collections.unmodifiableSet(ARTIFACT_UPDATE_TYPE_IDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of the most recently opened documents based on the
|
||||
* TSK_RECENT_OBJECT artifact.
|
||||
*
|
||||
* @param dataSource The data source to query.
|
||||
* @param maxCount The maximum number of results to return, pass 0 to get
|
||||
* a list of all results.
|
||||
*
|
||||
* @return A list RecentFileDetails representing the most recently opened
|
||||
* documents or an empty list if none were found.
|
||||
*
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public List<RecentFileDetails> getRecentlyOpenedDocuments(DataSource dataSource, int maxCount) throws SleuthkitCaseProviderException, TskCoreException {
|
||||
return recentSummary.getRecentlyOpenedDocuments(dataSource, maxCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of the most recent downloads based on the value of the the
|
||||
* artifact TSK_DATETIME_ACCESSED attribute.
|
||||
*
|
||||
* @param dataSource Data source to query.
|
||||
* @param maxCount Maximum number of results to return, passing 0 will
|
||||
* return all results.
|
||||
*
|
||||
* @return A list of RecentFileDetails objects or empty list if none were
|
||||
* found.
|
||||
*
|
||||
* @throws TskCoreException
|
||||
* @throws SleuthkitCaseProviderException
|
||||
*/
|
||||
public List<RecentDownloadDetails> getRecentDownloads(DataSource dataSource, int maxCount) throws TskCoreException, SleuthkitCaseProviderException {
|
||||
return recentSummary.getRecentDownloads(dataSource, maxCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of the most recent message attachments.
|
||||
*
|
||||
* @param dataSource Data source to query.
|
||||
* @param maxCount Maximum number of results to return, passing 0 will
|
||||
* return all results.
|
||||
*
|
||||
* @return A list of RecentFileDetails of the most recent attachments.
|
||||
*
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public List<RecentAttachmentDetails> getRecentAttachments(DataSource dataSource, int maxCount) throws SleuthkitCaseProviderException, TskCoreException {
|
||||
return recentSummary.getRecentAttachments(dataSource, maxCount);
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020 Basis Technology Corp.
|
||||
* Copyright 2020-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -27,20 +27,15 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentAttachmentDetails;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentDownloadDetails;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentFileDetails;
|
||||
import static org.sleuthkit.autopsy.datasourcesummary.ui.BaseDataSourceSummaryPanel.getTableExport;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.GuiCellModel.MenuItem;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel;
|
||||
@ -70,7 +65,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel {
|
||||
private final DataFetcher<DataSource, List<RecentAttachmentDetails>> attachmentsFetcher;
|
||||
|
||||
private final List<ColumnModel<RecentFileDetails, DefaultCellModel<?>>> docsTemplate = Arrays.asList(
|
||||
new ColumnModel<>(Bundle.RecentFilePanel_col_header_path(),
|
||||
new ColumnModel<>(Bundle.RecentFilesPanel_col_header_path(),
|
||||
(prog) -> {
|
||||
return new DefaultCellModel<>(prog.getPath())
|
||||
.setPopupMenuRetriever(getPopupFunct(prog));
|
||||
@ -80,12 +75,12 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel {
|
||||
80));
|
||||
|
||||
private final List<ColumnModel<RecentDownloadDetails, DefaultCellModel<?>>> downloadsTemplate = Arrays.asList(
|
||||
new ColumnModel<>(Bundle.RecentFilePanel_col_header_domain(),
|
||||
new ColumnModel<>(Bundle.RecentFilesPanel_col_header_domain(),
|
||||
(prog) -> {
|
||||
return new DefaultCellModel<>(prog.getWebDomain())
|
||||
.setPopupMenuRetriever(getPopupFunct(prog));
|
||||
}, 100),
|
||||
new ColumnModel<>(Bundle.RecentFilePanel_col_header_path(),
|
||||
new ColumnModel<>(Bundle.RecentFilesPanel_col_header_path(),
|
||||
(prog) -> {
|
||||
return new DefaultCellModel<>(prog.getPath())
|
||||
.setPopupMenuRetriever(getPopupFunct(prog));
|
||||
@ -95,7 +90,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel {
|
||||
80));
|
||||
|
||||
private final List<ColumnModel<RecentAttachmentDetails, DefaultCellModel<?>>> attachmentsTemplate = Arrays.asList(
|
||||
new ColumnModel<>(Bundle.RecentFilePanel_col_header_path(),
|
||||
new ColumnModel<>(Bundle.RecentFilesPanel_col_header_path(),
|
||||
(prog) -> {
|
||||
return new DefaultCellModel<>(prog.getPath())
|
||||
.setPopupMenuRetriever(getPopupFunct(prog));
|
||||
@ -103,7 +98,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel {
|
||||
new ColumnModel<>(Bundle.RecentFilesPanel_col_head_date(),
|
||||
getDateFunct(),
|
||||
80),
|
||||
new ColumnModel<>(Bundle.RecentFilePanel_col_header_sender(),
|
||||
new ColumnModel<>(Bundle.RecentFilesPanel_col_header_sender(),
|
||||
(prog) -> {
|
||||
return new DefaultCellModel<>(prog.getSender())
|
||||
.setPopupMenuRetriever(getPopupFunct(prog));
|
||||
@ -114,19 +109,18 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel {
|
||||
*/
|
||||
@Messages({
|
||||
"RecentFilesPanel_col_head_date=Date",
|
||||
"RecentFilePanel_col_header_domain=Domain",
|
||||
"RecentFilePanel_col_header_path=Path",
|
||||
"RecentFilePanel_col_header_sender=Sender",
|
||||
"RecentFilePanel_emailParserModuleName=Email Parser"
|
||||
"RecentFilesPanel_col_header_domain=Domain",
|
||||
"RecentFilesPanel_col_header_path=Path",
|
||||
"RecentFilesPanel_col_header_sender=Sender"
|
||||
})
|
||||
public RecentFilesPanel() {
|
||||
this(new RecentFilesSummary());
|
||||
this(new RecentFilesGetter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new form RecentFilesPanel
|
||||
*/
|
||||
public RecentFilesPanel(RecentFilesSummary dataHandler) {
|
||||
public RecentFilesPanel(RecentFilesGetter dataHandler) {
|
||||
super(dataHandler);
|
||||
docsFetcher = (dataSource) -> dataHandler.getRecentlyOpenedDocuments(dataSource, 10);
|
||||
downloadsFetcher = (dataSource) -> dataHandler.getRecentDownloads(dataSource, 10);
|
||||
@ -137,15 +131,16 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a function that gets the date from the RecentFileDetails object and
|
||||
* converts into a DefaultCellModel to be displayed in a table.
|
||||
* Returns a function that gets the date from the RecentFileDetails object
|
||||
* and converts into a DefaultCellModel to be displayed in a table.
|
||||
*
|
||||
* @return The function that determines the date cell from a RecentFileDetails object.
|
||||
* @return The function that determines the date cell from a
|
||||
* RecentFileDetails object.
|
||||
*/
|
||||
private <T extends RecentFileDetails> Function<T, DefaultCellModel<?>> getDateFunct() {
|
||||
return (T lastAccessed) -> {
|
||||
Function<Date, String> dateParser = (dt) -> dt == null ? "" : DATETIME_FORMAT.format(dt);
|
||||
return new DefaultCellModel<>(new Date(lastAccessed.getDateAsLong() * 1000), dateParser, DATETIME_FORMAT_STR)
|
||||
return new DefaultCellModel<>(new Date(lastAccessed.getDateAsLong() * 1000), dateParser)
|
||||
.setPopupMenuRetriever(getPopupFunct(lastAccessed));
|
||||
};
|
||||
}
|
||||
@ -155,9 +150,10 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel {
|
||||
* items.
|
||||
*
|
||||
* @param record The RecentFileDetails instance.
|
||||
*
|
||||
* @return The menu items list containing one action or navigating to the
|
||||
* appropriate artifact/file and closing the data source summary dialog if
|
||||
* open.
|
||||
* appropriate artifact/file and closing the data source summary
|
||||
* dialog if open.
|
||||
*/
|
||||
private Supplier<List<MenuItem>> getPopupFunct(RecentFileDetails record) {
|
||||
return () -> {
|
||||
@ -190,16 +186,6 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel {
|
||||
onNewDataSource(dataFetchComponents, tablePanelList, dataSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
List<ExcelExport.ExcelSheetExport> getExports(DataSource dataSource) {
|
||||
return Stream.of(
|
||||
getTableExport(docsFetcher, docsTemplate, Bundle.RecentFilesPanel_docsTable_tabName(), dataSource),
|
||||
getTableExport(downloadsFetcher, downloadsTemplate, Bundle.RecentFilesPanel_downloadsTable_tabName(), dataSource),
|
||||
getTableExport(attachmentsFetcher, attachmentsTemplate, Bundle.RecentFilesPanel_attachmentsTable_tabName(), dataSource))
|
||||
.filter(sheet -> sheet != null)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
ingestRunningLabel.unregister();
|
||||
@ -216,7 +202,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel {
|
||||
}
|
||||
|
||||
@Messages({
|
||||
"RecentFilePanel_no_open_documents=No recently open documents found."
|
||||
"RecentFilesPanel_no_open_documents=No recently open documents found."
|
||||
})
|
||||
/**
|
||||
* Setup the data model and columns for the recently open table.
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020 Basis Technology Corp.
|
||||
* Copyright 2020-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -19,8 +19,6 @@
|
||||
package org.sleuthkit.autopsy.datasourcesummary.ui;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel;
|
||||
|
||||
@ -45,28 +43,23 @@ public final class SizeRepresentationUtil {
|
||||
"SizeRepresentationUtil_units_petabytes=PB"
|
||||
})
|
||||
enum SizeUnit {
|
||||
BYTES(Bundle.SizeRepresentationUtil_units_bytes(), "#", 0),
|
||||
KB(Bundle.SizeRepresentationUtil_units_kilobytes(), "#,##0.00,", 1),
|
||||
MB(Bundle.SizeRepresentationUtil_units_megabytes(), "#,##0.00,,", 2),
|
||||
GB(Bundle.SizeRepresentationUtil_units_gigabytes(), "#,##0.00,,,", 3),
|
||||
TB(Bundle.SizeRepresentationUtil_units_terabytes(), "#,##0.00,,,,", 4),
|
||||
PB(Bundle.SizeRepresentationUtil_units_petabytes(), "#,##0.00,,,,,", 5);
|
||||
BYTES(Bundle.SizeRepresentationUtil_units_bytes(), 0),
|
||||
KB(Bundle.SizeRepresentationUtil_units_kilobytes(), 1),
|
||||
MB(Bundle.SizeRepresentationUtil_units_megabytes(), 2),
|
||||
GB(Bundle.SizeRepresentationUtil_units_gigabytes(), 3),
|
||||
TB(Bundle.SizeRepresentationUtil_units_terabytes(), 4),
|
||||
PB(Bundle.SizeRepresentationUtil_units_petabytes(), 5);
|
||||
|
||||
private final String suffix;
|
||||
private final String excelFormatString;
|
||||
private final long divisor;
|
||||
|
||||
/**
|
||||
* Main constructor.
|
||||
* @param suffix The string suffix to use for size unit.
|
||||
* @param excelFormatString The excel format string to use for this size unit.
|
||||
* @param power The power of 1000 of bytes for this size unit.
|
||||
*/
|
||||
SizeUnit(String suffix, String excelFormatString, int power) {
|
||||
SizeUnit(String suffix, int power) {
|
||||
this.suffix = suffix;
|
||||
|
||||
// based on https://www.mrexcel.com/board/threads/how-do-i-format-cells-to-show-gb-mb-kb.140135/
|
||||
this.excelFormatString = String.format("%s \"%s\"", excelFormatString, suffix);
|
||||
this.divisor = (long) Math.pow(SIZE_CONVERSION_CONSTANT, power);
|
||||
}
|
||||
|
||||
@ -77,13 +70,6 @@ public final class SizeRepresentationUtil {
|
||||
return suffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The excel format string to use for this size unit.
|
||||
*/
|
||||
public String getExcelFormatString() {
|
||||
return excelFormatString;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The divisor to convert from bytes to this unit.
|
||||
*/
|
||||
@ -114,8 +100,7 @@ public final class SizeRepresentationUtil {
|
||||
return SizeUnit.values()[0];
|
||||
}
|
||||
|
||||
for (int unitsIndex = 0; unitsIndex < SizeUnit.values().length; unitsIndex++) {
|
||||
SizeUnit unit = SizeUnit.values()[unitsIndex];
|
||||
for (SizeUnit unit : SizeUnit.values()) {
|
||||
long result = size / unit.getDivisor();
|
||||
if (result < SIZE_CONVERSION_CONSTANT) {
|
||||
return unit;
|
||||
@ -126,14 +111,14 @@ public final class SizeRepresentationUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a long size in bytes as a string formated to be read by users.
|
||||
* Get a long size in bytes as a string formatted to be read by users.
|
||||
*
|
||||
* @param size Long value representing a size in byte.s
|
||||
* @param format The means of formatting the number.
|
||||
* @param showFullSize Optionally show the number of bytes in the
|
||||
* datasource.
|
||||
*
|
||||
* @return Return a string formated with a user friendly version of the size
|
||||
* @return Return a string formatted with a user friendly version of the size
|
||||
* as a string, returns empty String when provided empty size.
|
||||
*/
|
||||
static String getSizeString(Long size, DecimalFormat format, boolean showFullSize) {
|
||||
@ -168,12 +153,7 @@ public final class SizeRepresentationUtil {
|
||||
if (bytes == null) {
|
||||
return new DefaultCellModel<>("");
|
||||
} else {
|
||||
SizeUnit unit = SizeRepresentationUtil.getSizeUnit(bytes);
|
||||
if (unit == null) {
|
||||
unit = SizeUnit.BYTES;
|
||||
}
|
||||
|
||||
return new DefaultCellModel<Long>(bytes, SizeRepresentationUtil::getSizeString, unit.getExcelFormatString());
|
||||
return new DefaultCellModel<>(bytes, SizeRepresentationUtil::getSizeString);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020 Basis Technology Corp.
|
||||
* Copyright 2020-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -20,39 +20,29 @@ package org.sleuthkit.autopsy.datasourcesummary.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.logging.Level;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Interval;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.openide.util.actions.CallableSystemAction;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineDataSourceUtils;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.DailyActivityAmount;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.TimelineSummaryData;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartExport;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartPanel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartPanel.OrderedKey;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries.OrderedKey;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries.BarChartItem;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.KeyValueItemExportable;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.TitledExportable;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableComponent;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableLabel;
|
||||
@ -78,20 +68,10 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final String EARLIEST_LATEST_FORMAT_STR = "MMM d, yyyy";
|
||||
private static final DateFormat EARLIEST_LATEST_FORMAT = getUtcFormat(EARLIEST_LATEST_FORMAT_STR);
|
||||
private static final DateFormat CHART_FORMAT = getUtcFormat("MMM d, yyyy");
|
||||
private static final DateFormat EARLIEST_LATEST_FORMAT = TimelineSummary.getUtcFormat(EARLIEST_LATEST_FORMAT_STR);
|
||||
private static final DateFormat CHART_FORMAT = TimelineSummary.getUtcFormat("MMM d, yyyy");
|
||||
private static final int MOST_RECENT_DAYS_COUNT = 30;
|
||||
|
||||
/**
|
||||
* Creates a DateFormat formatter that uses UTC for time zone.
|
||||
*
|
||||
* @param formatString The date format string.
|
||||
* @return The data format.
|
||||
*/
|
||||
private static DateFormat getUtcFormat(String formatString) {
|
||||
return new SimpleDateFormat(formatString, Locale.getDefault());
|
||||
}
|
||||
|
||||
// components displayed in the tab
|
||||
private final IngestRunningLabel ingestRunningLabel = new IngestRunningLabel();
|
||||
private final LoadableLabel earliestLabel = new LoadableLabel(Bundle.TimelinePanel_earliestLabel_title());
|
||||
@ -108,13 +88,13 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel {
|
||||
private final List<DataFetchComponents<DataSource, ?>> dataFetchComponents;
|
||||
|
||||
public TimelinePanel() {
|
||||
this(new TimelineSummary());
|
||||
this(new TimelineSummaryGetter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new form PastCasesPanel
|
||||
*/
|
||||
public TimelinePanel(TimelineSummary timelineData) {
|
||||
public TimelinePanel(TimelineSummaryGetter timelineData) {
|
||||
super(timelineData);
|
||||
|
||||
dataFetcher = (dataSource) -> timelineData.getData(dataSource, MOST_RECENT_DAYS_COUNT);
|
||||
@ -126,29 +106,18 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel {
|
||||
initComponents();
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a date using a DateFormat. In the event that the date is null,
|
||||
* returns a null string.
|
||||
*
|
||||
* @param date The date to format.
|
||||
* @param formatter The DateFormat to use to format the date.
|
||||
* @return The formatted string generated from the formatter or null if the
|
||||
* date is null.
|
||||
*/
|
||||
private static String formatDate(Date date, DateFormat formatter) {
|
||||
return date == null ? null : formatter.format(date);
|
||||
}
|
||||
|
||||
private static final Color FILE_EVT_COLOR = new Color(228, 22, 28);
|
||||
private static final Color ARTIFACT_EVT_COLOR = new Color(21, 227, 100);
|
||||
|
||||
/**
|
||||
* Converts DailyActivityAmount data retrieved from TimelineSummary into
|
||||
* data to be displayed as a bar chart.
|
||||
* Converts DailyActivityAmount data retrieved from TimelineSummaryGetter
|
||||
* into data to be displayed as a bar chart.
|
||||
*
|
||||
* @param recentDaysActivity The data retrieved from TimelineSummary.
|
||||
* @param recentDaysActivity The data retrieved from
|
||||
* TimelineSummaryGetter.
|
||||
* @param showIntermediateDates If true, shows all dates. If false, shows
|
||||
* only first and last date.
|
||||
*
|
||||
* @return The data to be displayed in the BarChart.
|
||||
*/
|
||||
private List<BarChartSeries> parseChartData(List<DailyActivityAmount> recentDaysActivity, boolean showIntermediateDates) {
|
||||
@ -167,7 +136,7 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel {
|
||||
long fileAmt = curItem.getFileActivityCount();
|
||||
long artifactAmt = curItem.getArtifactActivityCount() * 100;
|
||||
String formattedDate = (showIntermediateDates || i == 0 || i == recentDaysActivity.size() - 1)
|
||||
? formatDate(curItem.getDay(), CHART_FORMAT) : "";
|
||||
? TimelineSummary.formatDate(curItem.getDay(), CHART_FORMAT) : "";
|
||||
|
||||
OrderedKey thisKey = new OrderedKey(formattedDate, i);
|
||||
fileEvtCounts.add(new BarChartItem(thisKey, fileAmt));
|
||||
@ -191,8 +160,8 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel {
|
||||
* @param result The result to be displayed on this tab.
|
||||
*/
|
||||
private void handleResult(DataFetchResult<TimelineSummaryData> result) {
|
||||
earliestLabel.showDataFetchResult(DataFetchResult.getSubResult(result, r -> formatDate(r.getMinDate(), EARLIEST_LATEST_FORMAT)));
|
||||
latestLabel.showDataFetchResult(DataFetchResult.getSubResult(result, r -> formatDate(r.getMaxDate(), EARLIEST_LATEST_FORMAT)));
|
||||
earliestLabel.showDataFetchResult(DataFetchResult.getSubResult(result, r -> TimelineSummary.formatDate(r.getMinDate(), EARLIEST_LATEST_FORMAT)));
|
||||
latestLabel.showDataFetchResult(DataFetchResult.getSubResult(result, r -> TimelineSummary.formatDate(r.getMaxDate(), EARLIEST_LATEST_FORMAT)));
|
||||
last30DaysChart.showDataFetchResult(DataFetchResult.getSubResult(result, r -> parseChartData(r.getMostRecentDaysActivity(), false)));
|
||||
|
||||
if (result != null
|
||||
@ -266,7 +235,7 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel {
|
||||
if (minDate != null && maxDate != null) {
|
||||
timeSpan = new Interval(new DateTime(minDate), new DateTime(maxDate));
|
||||
}
|
||||
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "Unable to view time range in Timeline view", ex);
|
||||
}
|
||||
|
||||
@ -293,43 +262,6 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel {
|
||||
super.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a default cell model to be use with excel export in the earliest /
|
||||
* latest date format.
|
||||
*
|
||||
* @param date The date.
|
||||
* @return The cell model.
|
||||
*/
|
||||
private static DefaultCellModel<?> getEarliestLatestCell(Date date) {
|
||||
return new DefaultCellModel<>(date, (dt) -> dt == null ? "" : EARLIEST_LATEST_FORMAT.format(dt), EARLIEST_LATEST_FORMAT_STR);
|
||||
}
|
||||
|
||||
@Messages({
|
||||
"TimelinePanel_getExports_sheetName=Timeline",
|
||||
"TimelinePanel_getExports_activityRange=Activity Range",
|
||||
"TimelinePanel_getExports_earliest=Earliest:",
|
||||
"TimelinePanel_getExports_latest=Latest:",
|
||||
"TimelinePanel_getExports_dateColumnHeader=Date",
|
||||
"TimelinePanel_getExports_chartName=Last 30 Days",})
|
||||
@Override
|
||||
List<ExcelExport.ExcelSheetExport> getExports(DataSource dataSource) {
|
||||
TimelineSummaryData summaryData = getFetchResult(dataFetcher, "Timeline", dataSource);
|
||||
if (summaryData == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return Arrays.asList(
|
||||
new ExcelSpecialFormatExport(Bundle.TimelinePanel_getExports_sheetName(),
|
||||
Arrays.asList(
|
||||
new TitledExportable(Bundle.TimelinePanel_getExports_activityRange(), Collections.emptyList()),
|
||||
new KeyValueItemExportable(Bundle.TimelinePanel_getExports_earliest(), getEarliestLatestCell(summaryData.getMinDate())),
|
||||
new KeyValueItemExportable(Bundle.TimelinePanel_getExports_latest(), getEarliestLatestCell(summaryData.getMaxDate())),
|
||||
new BarChartExport(Bundle.TimelinePanel_getExports_dateColumnHeader(),
|
||||
"#,###",
|
||||
Bundle.TimelinePanel_getExports_chartName(),
|
||||
parseChartData(summaryData.getMostRecentDaysActivity(), true)))));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020 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.datasourcesummary.ui;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultUpdateGovernor;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.TimelineSummaryData;
|
||||
|
||||
/**
|
||||
* Provides data source summary information pertaining to Timeline data.
|
||||
*/
|
||||
public class TimelineSummaryGetter implements DefaultUpdateGovernor {
|
||||
|
||||
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS = new HashSet<>(
|
||||
Arrays.asList(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED));
|
||||
|
||||
private final TimelineSummary timelineSummary;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public TimelineSummaryGetter() {
|
||||
timelineSummary = new TimelineSummary();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshRequired(ModuleContentEvent evt) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshRequired(AbstractFile file) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshRequired(IngestManager.IngestJobEvent evt) {
|
||||
return (evt != null && INGEST_JOB_EVENTS.contains(evt));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<IngestManager.IngestJobEvent> getIngestJobEventUpdates() {
|
||||
return Collections.unmodifiableSet(INGEST_JOB_EVENTS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves timeline summary data.
|
||||
*
|
||||
* @param dataSource The data source for which timeline data will be
|
||||
* retrieved.
|
||||
* @param recentDaysNum The maximum number of most recent days' activity to
|
||||
* include.
|
||||
*
|
||||
* @return The retrieved data.
|
||||
*
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public TimelineSummaryData getData(DataSource dataSource, int recentDaysNum) throws SleuthkitCaseProviderException, TskCoreException {
|
||||
return timelineSummary.getTimelineSummaryData(dataSource, recentDaysNum);
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2019 Basis Technology Corp.
|
||||
* Copyright 2019-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -23,31 +23,23 @@ import java.sql.SQLException;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.coreutils.FileTypeUtils.FileTypeCategory;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.TypesSummary;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.MimeTypeSummary;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataSourceInfoUtilities;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.TypesSummary.FileTypeCategoryData;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult.ResultType;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.KeyValueItemExportable;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableComponent;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableLabel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.PieChartExport;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.PieChartPanel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.PieChartItem;
|
||||
|
||||
@ -95,7 +87,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
|
||||
* @param usefulContent True if this is useful content; false if there
|
||||
* is 0 mime type information.
|
||||
*/
|
||||
public TypesPieChartData(List<PieChartItem> pieSlices, boolean usefulContent) {
|
||||
TypesPieChartData(List<PieChartItem> pieSlices, boolean usefulContent) {
|
||||
this.pieSlices = pieSlices;
|
||||
this.usefulContent = usefulContent;
|
||||
}
|
||||
@ -103,78 +95,20 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
|
||||
/**
|
||||
* @return The pie chart data.
|
||||
*/
|
||||
public List<PieChartItem> getPieSlices() {
|
||||
List<PieChartItem> getPieSlices() {
|
||||
return pieSlices;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether or not the data is usefulContent.
|
||||
*/
|
||||
public boolean isUsefulContent() {
|
||||
boolean isUsefulContent() {
|
||||
return usefulContent;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Information concerning a particular category in the file types pie chart.
|
||||
*/
|
||||
private static class TypesPieCategory {
|
||||
|
||||
private final String label;
|
||||
private final Set<String> mimeTypes;
|
||||
private final Color color;
|
||||
|
||||
/**
|
||||
* Main constructor.
|
||||
*
|
||||
* @param label The label for this slice.
|
||||
* @param mimeTypes The mime types associated with this slice.
|
||||
* @param color The color associated with this slice.
|
||||
*/
|
||||
TypesPieCategory(String label, Set<String> mimeTypes, Color color) {
|
||||
this.label = label;
|
||||
this.mimeTypes = mimeTypes;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that accepts FileTypeCategory.
|
||||
*
|
||||
* @param label The label for this slice.
|
||||
* @param mimeTypes The mime types associated with this slice.
|
||||
* @param color The color associated with this slice.
|
||||
*/
|
||||
TypesPieCategory(String label, FileTypeCategory fileCategory, Color color) {
|
||||
this(label, fileCategory.getMediaTypes(), color);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The label for this category.
|
||||
*/
|
||||
String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The mime types associated with this category.
|
||||
*/
|
||||
Set<String> getMimeTypes() {
|
||||
return mimeTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The color associated with this category.
|
||||
*/
|
||||
Color getColor() {
|
||||
return color;
|
||||
}
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final DecimalFormat INTEGER_SIZE_FORMAT = new DecimalFormat("#");
|
||||
private static final String COMMA_FORMAT_STR = "#,###";
|
||||
|
||||
private static final DecimalFormat COMMA_FORMATTER = new DecimalFormat(COMMA_FORMAT_STR);
|
||||
|
||||
private static final Color IMAGES_COLOR = new Color(156, 39, 176);
|
||||
private static final Color VIDEOS_COLOR = Color.YELLOW;
|
||||
@ -186,13 +120,13 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
|
||||
private static final Color NOT_ANALYZED_COLOR = Color.WHITE;
|
||||
|
||||
// All file type categories.
|
||||
private static final List<TypesPieCategory> FILE_MIME_TYPE_CATEGORIES = Arrays.asList(
|
||||
new TypesPieCategory(Bundle.TypesPanel_fileMimeTypesChart_images_title(), FileTypeCategory.IMAGE.getMediaTypes(), IMAGES_COLOR),
|
||||
new TypesPieCategory(Bundle.TypesPanel_fileMimeTypesChart_videos_title(), FileTypeCategory.VIDEO.getMediaTypes(), VIDEOS_COLOR),
|
||||
new TypesPieCategory(Bundle.TypesPanel_fileMimeTypesChart_audio_title(), FileTypeCategory.AUDIO.getMediaTypes(), AUDIO_COLOR),
|
||||
new TypesPieCategory(Bundle.TypesPanel_fileMimeTypesChart_documents_title(), FileTypeCategory.DOCUMENTS.getMediaTypes(), DOCUMENTS_COLOR),
|
||||
new TypesPieCategory(Bundle.TypesPanel_fileMimeTypesChart_executables_title(), FileTypeCategory.EXECUTABLE.getMediaTypes(), EXECUTABLES_COLOR),
|
||||
new TypesPieCategory(Bundle.TypesPanel_fileMimeTypesChart_unknown_title(), new HashSet<>(Arrays.asList("application/octet-stream")), UNKNOWN_COLOR)
|
||||
private static final List<FileTypeCategoryData> FILE_MIME_TYPE_CATEGORIES = Arrays.asList(
|
||||
new FileTypeCategoryData(Bundle.TypesPanel_fileMimeTypesChart_images_title(), FileTypeCategory.IMAGE.getMediaTypes(), IMAGES_COLOR),
|
||||
new FileTypeCategoryData(Bundle.TypesPanel_fileMimeTypesChart_videos_title(), FileTypeCategory.VIDEO.getMediaTypes(), VIDEOS_COLOR),
|
||||
new FileTypeCategoryData(Bundle.TypesPanel_fileMimeTypesChart_audio_title(), FileTypeCategory.AUDIO.getMediaTypes(), AUDIO_COLOR),
|
||||
new FileTypeCategoryData(Bundle.TypesPanel_fileMimeTypesChart_documents_title(), FileTypeCategory.DOCUMENTS.getMediaTypes(), DOCUMENTS_COLOR),
|
||||
new FileTypeCategoryData(Bundle.TypesPanel_fileMimeTypesChart_executables_title(), FileTypeCategory.EXECUTABLE.getMediaTypes(), EXECUTABLES_COLOR),
|
||||
new FileTypeCategoryData(Bundle.TypesPanel_fileMimeTypesChart_unknown_title(), new HashSet<>(Arrays.asList("application/octet-stream")), UNKNOWN_COLOR)
|
||||
);
|
||||
|
||||
private final DataFetcher<DataSource, String> usageFetcher;
|
||||
@ -237,8 +171,8 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
|
||||
/**
|
||||
* Creates a new TypesPanel.
|
||||
*/
|
||||
public TypesPanel() {
|
||||
this(new MimeTypeSummary(), new TypesSummary(), new ContainerSummary());
|
||||
TypesPanel() {
|
||||
this(new MimeTypeSummaryGetter(), new TypesSummaryGetter(), new ContainerSummaryGetter());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -254,10 +188,10 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
|
||||
* @param typeData The service for file types data.
|
||||
* @param containerData The service for container information.
|
||||
*/
|
||||
public TypesPanel(
|
||||
MimeTypeSummary mimeTypeData,
|
||||
TypesSummary typeData,
|
||||
ContainerSummary containerData) {
|
||||
TypesPanel(
|
||||
MimeTypeSummaryGetter mimeTypeData,
|
||||
TypesSummaryGetter typeData,
|
||||
ContainerSummaryGetter containerData) {
|
||||
|
||||
super(mimeTypeData, typeData, containerData);
|
||||
|
||||
@ -282,13 +216,13 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
|
||||
size -> SizeRepresentationUtil.getSizeString(size, INTEGER_SIZE_FORMAT, false)))),
|
||||
new DataFetchWorker.DataFetchComponents<>(typesFetcher, this::showMimeTypeCategories),
|
||||
new DataFetchWorker.DataFetchComponents<>(allocatedFetcher,
|
||||
countRes -> allocatedLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> getStringOrZero(count)))),
|
||||
countRes -> allocatedLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> DataSourceInfoUtilities.getStringOrZero(count)))),
|
||||
new DataFetchWorker.DataFetchComponents<>(unallocatedFetcher,
|
||||
countRes -> unallocatedLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> getStringOrZero(count)))),
|
||||
countRes -> unallocatedLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> DataSourceInfoUtilities.getStringOrZero(count)))),
|
||||
new DataFetchWorker.DataFetchComponents<>(slackFetcher,
|
||||
countRes -> slackLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> getStringOrZero(count)))),
|
||||
countRes -> slackLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> DataSourceInfoUtilities.getStringOrZero(count)))),
|
||||
new DataFetchWorker.DataFetchComponents<>(directoriesFetcher,
|
||||
countRes -> directoriesLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> getStringOrZero(count))))
|
||||
countRes -> directoriesLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> DataSourceInfoUtilities.getStringOrZero(count))))
|
||||
);
|
||||
|
||||
initComponents();
|
||||
@ -312,7 +246,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
|
||||
*
|
||||
* @return The pie chart items.
|
||||
*/
|
||||
private TypesPieChartData getMimeTypeCategoriesModel(MimeTypeSummary mimeTypeData, DataSource dataSource)
|
||||
private TypesPieChartData getMimeTypeCategoriesModel(MimeTypeSummaryGetter mimeTypeData, DataSource dataSource)
|
||||
throws SQLException, SleuthkitCaseProviderException, TskCoreException {
|
||||
|
||||
if (dataSource == null) {
|
||||
@ -323,8 +257,8 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
|
||||
List<PieChartItem> fileCategoryItems = new ArrayList<>();
|
||||
long categoryTotalCount = 0;
|
||||
|
||||
for (TypesPieCategory cat : FILE_MIME_TYPE_CATEGORIES) {
|
||||
long thisValue = getLongOrZero(mimeTypeData.getCountOfFilesForMimeTypes(dataSource, cat.getMimeTypes()));
|
||||
for (FileTypeCategoryData cat : FILE_MIME_TYPE_CATEGORIES) {
|
||||
long thisValue = DataSourceInfoUtilities.getLongOrZero(mimeTypeData.getCountOfFilesForMimeTypes(dataSource, cat.getMimeTypes()));
|
||||
categoryTotalCount += thisValue;
|
||||
|
||||
fileCategoryItems.add(new PieChartItem(
|
||||
@ -334,10 +268,10 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
|
||||
}
|
||||
|
||||
// get a count of all files with no mime type
|
||||
long noMimeTypeCount = getLongOrZero(mimeTypeData.getCountOfFilesWithNoMimeType(dataSource));
|
||||
long noMimeTypeCount = DataSourceInfoUtilities.getLongOrZero(mimeTypeData.getCountOfFilesWithNoMimeType(dataSource));
|
||||
|
||||
// get a count of all regular files
|
||||
long allRegularFiles = getLongOrZero(mimeTypeData.getCountOfAllRegularFiles(dataSource));
|
||||
long allRegularFiles = DataSourceInfoUtilities.getLongOrZero(mimeTypeData.getCountOfAllRegularFiles(dataSource));
|
||||
|
||||
// create entry for mime types in other category
|
||||
long otherCount = allRegularFiles - (categoryTotalCount + noMimeTypeCount);
|
||||
@ -390,89 +324,6 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the long value or zero if longVal is null.
|
||||
*
|
||||
* @param longVal The long value.
|
||||
*
|
||||
* @return The long value or 0 if provided value is null.
|
||||
*/
|
||||
private static long getLongOrZero(Long longVal) {
|
||||
return longVal == null ? 0 : longVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns string value of long with comma separators. If null returns a
|
||||
* string of '0'.
|
||||
*
|
||||
* @param longVal The long value.
|
||||
*
|
||||
* @return The string value of the long.
|
||||
*/
|
||||
private static String getStringOrZero(Long longVal) {
|
||||
return longVal == null ? "0" : COMMA_FORMATTER.format(longVal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a key value pair to be exported in a sheet.
|
||||
*
|
||||
* @param fetcher The means of fetching the data.
|
||||
* @param key The key to use.
|
||||
* @param dataSource The data source containing the data.
|
||||
* @return The key value pair to be exported.
|
||||
*/
|
||||
private static KeyValueItemExportable getStrExportable(DataFetcher<DataSource, String> fetcher, String key, DataSource dataSource) {
|
||||
String result = getFetchResult(fetcher, "Types", dataSource);
|
||||
return (result == null) ? null : new KeyValueItemExportable(key, new DefaultCellModel<>(result));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a key value pair to be exported in a sheet formatting the long
|
||||
* with commas separated by orders of 1000.
|
||||
*
|
||||
* @param fetcher The means of fetching the data.
|
||||
* @param key The string key for this key value pair.
|
||||
* @param dataSource The data source.
|
||||
* @return The key value pair.
|
||||
*/
|
||||
private static KeyValueItemExportable getCountExportable(DataFetcher<DataSource, Long> fetcher, String key, DataSource dataSource) {
|
||||
Long count = getFetchResult(fetcher, "Types", dataSource);
|
||||
return (count == null) ? null : new KeyValueItemExportable(key,
|
||||
new DefaultCellModel<Long>(count, COMMA_FORMATTER::format, COMMA_FORMAT_STR));
|
||||
}
|
||||
|
||||
@Override
|
||||
List<ExcelExport.ExcelSheetExport> getExports(DataSource dataSource) {
|
||||
if (dataSource == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// Retrieve data to create the types pie chart
|
||||
TypesPieChartData typesData = TypesPanel.getFetchResult(typesFetcher, "Types", dataSource);
|
||||
PieChartExport typesChart = (typesData == null || !typesData.isUsefulContent()) ? null :
|
||||
new PieChartExport(
|
||||
Bundle.TypesPanel_fileMimeTypesChart_title(),
|
||||
Bundle.TypesPanel_fileMimeTypesChart_valueLabel(),
|
||||
"#,###",
|
||||
Bundle.TypesPanel_fileMimeTypesChart_title(),
|
||||
typesData.getPieSlices());
|
||||
|
||||
return Arrays.asList(new ExcelSpecialFormatExport(Bundle.TypesPanel_excelTabName(),
|
||||
Stream.of(
|
||||
getStrExportable(usageFetcher, Bundle.TypesPanel_usageLabel_title(), dataSource),
|
||||
getStrExportable(osFetcher, Bundle.TypesPanel_osLabel_title(), dataSource),
|
||||
new KeyValueItemExportable(Bundle.TypesPanel_sizeLabel_title(),
|
||||
SizeRepresentationUtil.getBytesCell(getFetchResult(sizeFetcher, "Types", dataSource))),
|
||||
typesChart,
|
||||
getCountExportable(allocatedFetcher, Bundle.TypesPanel_filesByCategoryTable_allocatedRow_title(), dataSource),
|
||||
getCountExportable(unallocatedFetcher, Bundle.TypesPanel_filesByCategoryTable_unallocatedRow_title(), dataSource),
|
||||
getCountExportable(slackFetcher, Bundle.TypesPanel_filesByCategoryTable_slackRow_title(), dataSource),
|
||||
getCountExportable(directoriesFetcher, Bundle.TypesPanel_filesByCategoryTable_directoryRow_title(), dataSource))
|
||||
.filter(sheet -> sheet != null)
|
||||
.collect(Collectors.toList())
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2019 - 2020 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.datasourcesummary.ui;
|
||||
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultUpdateGovernor;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.TypesSummary;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Wrapper class for converting org.sleuthkit.autopsy.contentutils.TypesSummary
|
||||
* functionality into a DefaultArtifactUpdateGovernor used by
|
||||
* DataSourceSummaryCountsPanel.
|
||||
*/
|
||||
public class TypesSummaryGetter implements DefaultUpdateGovernor {
|
||||
|
||||
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS = new HashSet<>(
|
||||
Arrays.asList(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED));
|
||||
|
||||
private final TypesSummary typesSummary;
|
||||
|
||||
/**
|
||||
* Main constructor.
|
||||
*/
|
||||
public TypesSummaryGetter() {
|
||||
typesSummary = new TypesSummary();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshRequired(ModuleContentEvent evt) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshRequired(AbstractFile file) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshRequired(IngestManager.IngestJobEvent evt) {
|
||||
return (evt != null && INGEST_JOB_EVENTS.contains(evt));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<IngestManager.IngestJobEvent> getIngestJobEventUpdates() {
|
||||
return Collections.unmodifiableSet(INGEST_JOB_EVENTS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get count of regular files (not directories) in a data source.
|
||||
*
|
||||
* @param currentDataSource The data source.
|
||||
*
|
||||
* @return The count.
|
||||
*
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
* @throws SQLException
|
||||
*/
|
||||
public Long getCountOfFiles(DataSource currentDataSource)
|
||||
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
|
||||
return typesSummary.getCountOfFiles(currentDataSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get count of allocated files in a data source.
|
||||
*
|
||||
* @param currentDataSource The data source.
|
||||
*
|
||||
* @return The count.
|
||||
*
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
* @throws SQLException
|
||||
*/
|
||||
public Long getCountOfAllocatedFiles(DataSource currentDataSource)
|
||||
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
|
||||
return typesSummary.getCountOfAllocatedFiles(currentDataSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get count of unallocated files in a data source.
|
||||
*
|
||||
* @param currentDataSource The data source.
|
||||
*
|
||||
* @return The count.
|
||||
*
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
* @throws SQLException
|
||||
*/
|
||||
public Long getCountOfUnallocatedFiles(DataSource currentDataSource)
|
||||
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
|
||||
return typesSummary.getCountOfUnallocatedFiles(currentDataSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get count of directories in a data source.
|
||||
*
|
||||
* @param currentDataSource The data source.
|
||||
*
|
||||
* @return The count.
|
||||
*
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
* @throws SQLException
|
||||
*/
|
||||
public Long getCountOfDirectories(DataSource currentDataSource)
|
||||
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
|
||||
return typesSummary.getCountOfDirectories(currentDataSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get count of slack files in a data source.
|
||||
*
|
||||
* @param currentDataSource The data source.
|
||||
*
|
||||
* @return The count.
|
||||
*
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
* @throws SQLException
|
||||
*/
|
||||
public Long getCountOfSlackFiles(DataSource currentDataSource)
|
||||
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
|
||||
return typesSummary.getCountOfSlackFiles(currentDataSource);
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020 Basis Technology Corp.
|
||||
* Copyright 2020-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -26,23 +26,19 @@ import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.LastAccessedArtifact;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopAccountResult;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopDeviceAttachedResult;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopWebSearchResult;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopDomainsResult;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopProgramsResult;
|
||||
import static org.sleuthkit.autopsy.datasourcesummary.ui.BaseDataSourceSummaryPanel.getTableExport;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopWebSearchResult;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.GuiCellModel.MenuItem;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel;
|
||||
@ -265,13 +261,13 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel {
|
||||
private final IngestRunningLabel ingestRunningLabel = new IngestRunningLabel();
|
||||
|
||||
private final List<DataFetchComponents<DataSource, ?>> dataFetchComponents;
|
||||
private final UserActivitySummary userActivityData;
|
||||
private final UserActivitySummaryGetter userActivityData;
|
||||
|
||||
/**
|
||||
* Creates a new UserActivityPanel.
|
||||
*/
|
||||
public UserActivityPanel() {
|
||||
this(new UserActivitySummary());
|
||||
this(new UserActivitySummaryGetter());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -280,7 +276,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel {
|
||||
* @param userActivityData Class from which to obtain remaining user
|
||||
* activity data.
|
||||
*/
|
||||
public UserActivityPanel(UserActivitySummary userActivityData) {
|
||||
public UserActivityPanel(UserActivitySummaryGetter userActivityData) {
|
||||
super(userActivityData);
|
||||
this.userActivityData = userActivityData;
|
||||
|
||||
@ -320,7 +316,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel {
|
||||
private <T extends LastAccessedArtifact> Function<T, DefaultCellModel<?>> getDateFunct() {
|
||||
return (T lastAccessed) -> {
|
||||
Function<Date, String> dateParser = (dt) -> dt == null ? "" : DATETIME_FORMAT.format(dt);
|
||||
return new DefaultCellModel<>(lastAccessed.getLastAccessed(), dateParser, DATETIME_FORMAT_STR)
|
||||
return new DefaultCellModel<>(lastAccessed.getLastAccessed(), dateParser)
|
||||
.setPopupMenu(getPopup(lastAccessed));
|
||||
};
|
||||
}
|
||||
@ -332,7 +328,8 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel {
|
||||
* @param record The LastAccessedArtifact instance.
|
||||
*
|
||||
* @return The menu items list containing one action or navigating to the
|
||||
* appropriate artifact and closing the data source summary dialog if open.
|
||||
* appropriate artifact and closing the data source summary dialog
|
||||
* if open.
|
||||
*/
|
||||
private List<MenuItem> getPopup(LastAccessedArtifact record) {
|
||||
return record == null ? null : Arrays.asList(getArtifactNavigateItem(record.getArtifact()));
|
||||
@ -346,8 +343,8 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel {
|
||||
*
|
||||
* @return The underlying short folder name if one exists.
|
||||
*/
|
||||
private String getShortFolderName(String path, String appName) {
|
||||
return this.userActivityData.getShortFolderName(path, appName);
|
||||
private static String getShortFolderName(String path, String appName) {
|
||||
return UserActivitySummary.getShortFolderName(path, appName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -366,18 +363,6 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel {
|
||||
super.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
List<ExcelExport.ExcelSheetExport> getExports(DataSource dataSource) {
|
||||
return Stream.of(
|
||||
getTableExport(topProgramsFetcher, topProgramsTemplate, Bundle.UserActivityPanel_TopProgramsTableModel_tabName(), dataSource),
|
||||
getTableExport(topDomainsFetcher, topDomainsTemplate, Bundle.UserActivityPanel_TopDomainsTableModel_tabName(), dataSource),
|
||||
getTableExport(topWebSearchesFetcher, topWebSearchesTemplate, Bundle.UserActivityPanel_TopWebSearchTableModel_tabName(), dataSource),
|
||||
getTableExport(topDevicesAttachedFetcher, topDevicesTemplate, Bundle.UserActivityPanel_TopDeviceAttachedTableModel_tabName(), dataSource),
|
||||
getTableExport(topAccountsFetcher, topAccountsTemplate, Bundle.UserActivityPanel_TopAccountTableModel_tabName(), dataSource))
|
||||
.filter(sheet -> sheet != null)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020-2021 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.datasourcesummary.ui;
|
||||
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopAccountResult;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopDeviceAttachedResult;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopDomainsResult;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopProgramsResult;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopWebSearchResult;
|
||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||
|
||||
/**
|
||||
* Wrapper class for converting
|
||||
* org.sleuthkit.autopsy.contentutils.UserActivitySummary functionality into a
|
||||
* DefaultArtifactUpdateGovernor used by UserActivityPanel tab.
|
||||
*/
|
||||
public class UserActivitySummaryGetter implements DefaultArtifactUpdateGovernor {
|
||||
|
||||
private static final Set<Integer> ARTIFACT_UPDATE_TYPE_IDS = new HashSet<>(Arrays.asList(
|
||||
ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID(),
|
||||
ARTIFACT_TYPE.TSK_MESSAGE.getTypeID(),
|
||||
ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID(),
|
||||
ARTIFACT_TYPE.TSK_CALLLOG.getTypeID(),
|
||||
ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID(),
|
||||
ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID(),
|
||||
ARTIFACT_TYPE.TSK_PROG_RUN.getTypeID()
|
||||
));
|
||||
|
||||
private final UserActivitySummary userActivity;
|
||||
|
||||
public UserActivitySummaryGetter() {
|
||||
userActivity = new UserActivitySummary();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Integer> getArtifactTypeIdsForRefresh() {
|
||||
return Collections.unmodifiableSet(ARTIFACT_UPDATE_TYPE_IDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of recent domains based on the datasource.
|
||||
*
|
||||
* @param dataSource The datasource to query for recent domains.
|
||||
* @param count The max count of items to return.
|
||||
*
|
||||
* @return The list of items retrieved from the database.
|
||||
*
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public List<TopDomainsResult> getRecentDomains(DataSource dataSource, int count) throws TskCoreException, SleuthkitCaseProviderException {
|
||||
return userActivity.getRecentDomains(dataSource, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves most recent web searches by most recent date grouped by search
|
||||
* term.
|
||||
*
|
||||
* @param dataSource The data source.
|
||||
* @param count The maximum number of records to be shown (must be >
|
||||
* 0).
|
||||
*
|
||||
* @return The list of most recent web searches where most recent search
|
||||
* appears first.
|
||||
*
|
||||
* @throws
|
||||
* org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public List<TopWebSearchResult> getMostRecentWebSearches(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException {
|
||||
return userActivity.getMostRecentWebSearches(dataSource, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves most recent devices used by most recent date attached.
|
||||
*
|
||||
* @param dataSource The data source.
|
||||
* @param count The maximum number of records to be shown (must be >
|
||||
* 0).
|
||||
*
|
||||
* @return The list of most recent devices attached where most recent device
|
||||
* attached appears first.
|
||||
*
|
||||
* @throws
|
||||
* org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public List<TopDeviceAttachedResult> getRecentDevices(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException {
|
||||
return userActivity.getRecentDevices(dataSource, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves most recent account used by most recent date for a message
|
||||
* sent.
|
||||
*
|
||||
* @param dataSource The data source.
|
||||
* @param count The maximum number of records to be shown (must be >
|
||||
* 0).
|
||||
*
|
||||
* @return The list of most recent accounts used where the most recent
|
||||
* account by last message sent occurs first.
|
||||
*
|
||||
* @throws
|
||||
* org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
@Messages({
|
||||
"DataSourceUserActivitySummary_getRecentAccounts_emailMessage=Email Message",
|
||||
"DataSourceUserActivitySummary_getRecentAccounts_calllogMessage=Call Log",})
|
||||
public List<TopAccountResult> getRecentAccounts(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException {
|
||||
return userActivity.getRecentAccounts(dataSource, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the top programs results for the given data source limited to
|
||||
* the count provided as a parameter. The highest run times are at the top
|
||||
* of the list. If that information isn't available the last run date is
|
||||
* used. If both, the last run date and the number of run times are
|
||||
* unavailable, the programs will be sorted alphabetically, the count will
|
||||
* be ignored and all items will be returned.
|
||||
*
|
||||
* @param dataSource The datasource. If the datasource is null, an empty
|
||||
* list will be returned.
|
||||
* @param count The number of results to return. This value must be > 0
|
||||
* or an IllegalArgumentException will be thrown.
|
||||
*
|
||||
* @return The sorted list and limited to the count if last run or run count
|
||||
* information is available on any item.
|
||||
*
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public List<TopProgramsResult> getTopPrograms(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException {
|
||||
return userActivity.getTopPrograms(dataSource, count);
|
||||
}
|
||||
}
|
@ -39,84 +39,6 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries.BarChartIt
|
||||
*/
|
||||
public class BarChartPanel extends AbstractLoadableComponent<List<BarChartSeries>> {
|
||||
|
||||
/**
|
||||
* JFreeChart bar charts don't preserve the order of bars provided to the
|
||||
* chart, but instead uses the comparable nature to order items. This
|
||||
* provides order using a provided index as well as the value for the axis.
|
||||
*/
|
||||
public static class OrderedKey implements Comparable<OrderedKey> {
|
||||
|
||||
private final Object keyValue;
|
||||
private final int keyIndex;
|
||||
|
||||
/**
|
||||
* Main constructor.
|
||||
*
|
||||
* @param keyValue The value for the key to be displayed in the domain
|
||||
* axis.
|
||||
* @param keyIndex The index at which it will be displayed.
|
||||
*/
|
||||
public OrderedKey(Object keyValue, int keyIndex) {
|
||||
this.keyValue = keyValue;
|
||||
this.keyIndex = keyIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The value for the key to be displayed in the domain axis.
|
||||
*/
|
||||
Object getKeyValue() {
|
||||
return keyValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The index at which it will be displayed.
|
||||
*/
|
||||
int getKeyIndex() {
|
||||
return keyIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(OrderedKey o) {
|
||||
// this will have a higher value than null.
|
||||
if (o == null) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// compare by index
|
||||
return Integer.compare(this.getKeyIndex(), o.getKeyIndex());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 3;
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final OrderedKey other = (OrderedKey) obj;
|
||||
if (this.keyIndex != other.keyIndex) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
// use toString on the key.
|
||||
return this.getKeyValue() == null ? null : this.getKeyValue().toString();
|
||||
}
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final Font DEFAULT_FONT = new JLabel().getFont();
|
||||
|
@ -98,4 +98,82 @@ public class BarChartSeries {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* JFreeChart bar charts don't preserve the order of bars provided to the
|
||||
* chart, but instead uses the comparable nature to order items. This
|
||||
* provides order using a provided index as well as the value for the axis.
|
||||
*/
|
||||
public static class OrderedKey implements Comparable<OrderedKey> {
|
||||
|
||||
private final Object keyValue;
|
||||
private final int keyIndex;
|
||||
|
||||
/**
|
||||
* Main constructor.
|
||||
*
|
||||
* @param keyValue The value for the key to be displayed in the domain
|
||||
* axis.
|
||||
* @param keyIndex The index at which it will be displayed.
|
||||
*/
|
||||
public OrderedKey(Object keyValue, int keyIndex) {
|
||||
this.keyValue = keyValue;
|
||||
this.keyIndex = keyIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The value for the key to be displayed in the domain axis.
|
||||
*/
|
||||
Object getKeyValue() {
|
||||
return keyValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The index at which it will be displayed.
|
||||
*/
|
||||
int getKeyIndex() {
|
||||
return keyIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(OrderedKey o) {
|
||||
// this will have a higher value than null.
|
||||
if (o == null) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// compare by index
|
||||
return Integer.compare(this.getKeyIndex(), o.getKeyIndex());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 3;
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final OrderedKey other = (OrderedKey) obj;
|
||||
if (this.keyIndex != other.keyIndex) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
// use toString on the key.
|
||||
return this.getKeyValue() == null ? null : this.getKeyValue().toString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
AbstractLoadableComponent_errorMessage_defaultText=There was an error loading results.
|
||||
AbstractLoadableComponent_loadingMessage_defaultText=Loading results...
|
||||
AbstractLoadableComponent_noDataExists_defaultText=No data exists.
|
||||
# {0} - sheetNumber
|
||||
ExcelExport_writeExcel_noSheetName=Sheet {0}
|
||||
IngestRunningLabel_defaultMessage=Ingest is currently running.
|
||||
PieChartPanel_noDataLabel=No Data
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datasourcesummary.uiutils;
|
||||
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.function.Consumer;
|
||||
import javax.swing.SwingWorker;
|
||||
|
@ -27,7 +27,7 @@ import java.util.function.Supplier;
|
||||
/**
|
||||
* The default cell model.
|
||||
*/
|
||||
public class DefaultCellModel<T> implements GuiCellModel, ExcelCellModel {
|
||||
public class DefaultCellModel<T> implements GuiCellModel {
|
||||
|
||||
private final T data;
|
||||
private final String text;
|
||||
@ -35,7 +35,6 @@ public class DefaultCellModel<T> implements GuiCellModel, ExcelCellModel {
|
||||
private CellModel.HorizontalAlign horizontalAlignment;
|
||||
private List<MenuItem> popupMenu;
|
||||
private Supplier<List<MenuItem>> menuItemSupplier;
|
||||
private final String excelFormatString;
|
||||
|
||||
/**
|
||||
* Main constructor.
|
||||
@ -43,7 +42,7 @@ public class DefaultCellModel<T> implements GuiCellModel, ExcelCellModel {
|
||||
* @param data The data to be displayed in the cell.
|
||||
*/
|
||||
public DefaultCellModel(T data) {
|
||||
this(data, null, null);
|
||||
this(data, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -54,24 +53,7 @@ public class DefaultCellModel<T> implements GuiCellModel, ExcelCellModel {
|
||||
* null to use .toString method on object.
|
||||
*/
|
||||
public DefaultCellModel(T data, Function<T, String> stringConverter) {
|
||||
this(data, stringConverter, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param data The data to be displayed in the cell.
|
||||
* @param stringConverter The means of converting that data to a string or
|
||||
* null to use .toString method on object.
|
||||
* @param excelFormatString The apache poi excel format string to use with
|
||||
* the data.
|
||||
*
|
||||
* NOTE: Only certain data types can be exported. See
|
||||
* ExcelTableExport.createCell() for types.
|
||||
*/
|
||||
public DefaultCellModel(T data, Function<T, String> stringConverter, String excelFormatString) {
|
||||
this.data = data;
|
||||
this.excelFormatString = excelFormatString;
|
||||
|
||||
if (stringConverter == null) {
|
||||
text = this.data == null ? "" : this.data.toString();
|
||||
@ -86,11 +68,6 @@ public class DefaultCellModel<T> implements GuiCellModel, ExcelCellModel {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExcelFormatString() {
|
||||
return this.excelFormatString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
return text;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2018 Basis Technology Corp.
|
||||
* Copyright 2011-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -26,6 +26,7 @@ import javax.swing.event.DocumentListener;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.casemodule.GeneralFilter;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.guiutils.JFileChooserFactory;
|
||||
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
|
||||
|
||||
/**
|
||||
@ -35,7 +36,9 @@ import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
|
||||
class AddExternalViewerRulePanel extends javax.swing.JPanel {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(AddExternalViewerRulePanel.class.getName());
|
||||
private final JFileChooser fc = new JFileChooser();
|
||||
private static final long serialVersionUID = 1L;
|
||||
private JFileChooser fc;
|
||||
private final JFileChooserFactory chooserHelper = new JFileChooserFactory();
|
||||
private static final GeneralFilter exeFilter = new GeneralFilter(GeneralFilter.EXECUTABLE_EXTS, GeneralFilter.EXECUTABLE_DESC);
|
||||
|
||||
enum EVENT {
|
||||
@ -47,10 +50,6 @@ class AddExternalViewerRulePanel extends javax.swing.JPanel {
|
||||
*/
|
||||
AddExternalViewerRulePanel() {
|
||||
initComponents();
|
||||
fc.setDragEnabled(false);
|
||||
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||
fc.setMultiSelectionEnabled(false);
|
||||
fc.setFileFilter(exeFilter);
|
||||
customize();
|
||||
}
|
||||
|
||||
@ -260,6 +259,13 @@ class AddExternalViewerRulePanel extends javax.swing.JPanel {
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed
|
||||
if(fc == null) {
|
||||
fc = chooserHelper.getChooser();
|
||||
fc.setDragEnabled(false);
|
||||
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||
fc.setMultiSelectionEnabled(false);
|
||||
fc.setFileFilter(exeFilter);
|
||||
}
|
||||
int returnState = fc.showOpenDialog(this);
|
||||
if (returnState == JFileChooser.APPROVE_OPTION) {
|
||||
String path = fc.getSelectedFile().getPath();
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2019 Basis Technology Corp.
|
||||
* Copyright 2019-2021 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.autopsy.datamodel.AbstractAbstractFileNode.AbstractFileProp
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.nodes.Node.PropertySet;
|
||||
import org.openide.nodes.Node.Property;
|
||||
import org.sleuthkit.autopsy.guiutils.JFileChooserFactory;
|
||||
|
||||
/**
|
||||
* Exports CSV version of result nodes to a location selected by the user.
|
||||
@ -69,6 +70,8 @@ public final class ExportCSVAction extends AbstractAction {
|
||||
// node in the array returns a reference to the same action object from Node.getActions(boolean).
|
||||
private static ExportCSVAction instance;
|
||||
|
||||
private static final JFileChooserFactory chooserHelper = new JFileChooserFactory();
|
||||
|
||||
/**
|
||||
* Get an instance of the Action. See above for why
|
||||
* the class is a singleton.
|
||||
@ -125,7 +128,7 @@ public final class ExportCSVAction extends AbstractAction {
|
||||
// Set up the file chooser with a default name and either the Export
|
||||
// folder or the last used folder.
|
||||
String fileName = getDefaultOutputFileName(nodesToExport.iterator().next().getParentNode());
|
||||
JFileChooser fileChooser = new JFileChooser();
|
||||
JFileChooser fileChooser = chooserHelper.getChooser();
|
||||
fileChooser.setCurrentDirectory(new File(getExportDirectory(Case.getCurrentCaseThrows())));
|
||||
fileChooser.setSelectedFile(new File(fileName));
|
||||
fileChooser.setFileFilter(new FileNameExtensionFilter("csv file", "csv"));
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2018 Basis Technology Corp.
|
||||
* Copyright 2011-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -33,6 +33,7 @@ import org.netbeans.spi.options.OptionsPanelController;
|
||||
import org.sleuthkit.autopsy.casemodule.GeneralFilter;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
||||
import org.sleuthkit.autopsy.guiutils.JFileChooserFactory;
|
||||
|
||||
/**
|
||||
* An options panel for the user to create, edit, and delete associations for
|
||||
@ -42,9 +43,13 @@ import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
||||
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
||||
final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel implements OptionsPanel {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private ExternalViewerGlobalSettingsTableModel tableModel;
|
||||
|
||||
public ExternalViewerGlobalSettingsPanel() {
|
||||
private final JFileChooserFactory chooserHelper = new JFileChooserFactory();
|
||||
|
||||
ExternalViewerGlobalSettingsPanel() {
|
||||
this(new ExternalViewerGlobalSettingsTableModel(new String[] {
|
||||
"Mime type/Extension", "Application"}));
|
||||
}
|
||||
@ -52,7 +57,7 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme
|
||||
/**
|
||||
* Creates new form ExternalViewerGlobalSettingsPanel
|
||||
*/
|
||||
public ExternalViewerGlobalSettingsPanel(ExternalViewerGlobalSettingsTableModel tableModel) {
|
||||
ExternalViewerGlobalSettingsPanel(ExternalViewerGlobalSettingsTableModel tableModel) {
|
||||
initComponents();
|
||||
this.tableModel = tableModel;
|
||||
customizeComponents(tableModel);
|
||||
@ -335,7 +340,7 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme
|
||||
}//GEN-LAST:event_deleteRuleButtonActionPerformed
|
||||
|
||||
private void browseHxDDirectoryActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseHxDDirectoryActionPerformed
|
||||
JFileChooser fileWindow = new JFileChooser();
|
||||
JFileChooser fileWindow = chooserHelper.getChooser();
|
||||
fileWindow.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||
GeneralFilter exeFilter = new GeneralFilter(GeneralFilter.EXECUTABLE_EXTS, GeneralFilter.EXECUTABLE_DESC);
|
||||
File HxDPathFile = new File(HxDPath.getText());
|
||||
|
@ -33,9 +33,6 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.JFileChooser;
|
||||
@ -50,6 +47,7 @@ import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.autopsy.guiutils.JFileChooserFactory;
|
||||
import org.sleuthkit.datamodel.AbstractContent;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
@ -78,9 +76,7 @@ final class ExtractUnallocAction extends AbstractAction {
|
||||
private final Volume volume;
|
||||
private final Image image;
|
||||
|
||||
private final FutureTask<JFileChooser> futureFileChooser = new FutureTask<>(CustomFileChooser::new);
|
||||
|
||||
private JFileChooser fileChooser = null;
|
||||
private final JFileChooserFactory chooserFactory;
|
||||
|
||||
/**
|
||||
* Create an instance of ExtractUnallocAction with a volume.
|
||||
@ -111,8 +107,7 @@ final class ExtractUnallocAction extends AbstractAction {
|
||||
this.volume = null;
|
||||
this.image = image;
|
||||
|
||||
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
executor.execute(futureFileChooser);
|
||||
chooserFactory = new JFileChooserFactory(CustomFileChooser.class);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -138,13 +133,7 @@ final class ExtractUnallocAction extends AbstractAction {
|
||||
return;
|
||||
}
|
||||
|
||||
if (fileChooser == null) {
|
||||
try {
|
||||
fileChooser = futureFileChooser.get();
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
fileChooser = new CustomFileChooser();
|
||||
}
|
||||
}
|
||||
JFileChooser fileChooser = chooserFactory.getChooser();
|
||||
|
||||
fileChooser.setCurrentDirectory(new File(getExportDirectory(openCase)));
|
||||
if (JFileChooser.APPROVE_OPTION != fileChooser.showSaveDialog((Component) event.getSource())) {
|
||||
@ -753,11 +742,11 @@ final class ExtractUnallocAction extends AbstractAction {
|
||||
}
|
||||
|
||||
// A Custome JFileChooser for this Action Class.
|
||||
private class CustomFileChooser extends JFileChooser {
|
||||
public static class CustomFileChooser extends JFileChooser {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
CustomFileChooser() {
|
||||
public CustomFileChooser() {
|
||||
initalize();
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Copyright 2011-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -28,14 +28,26 @@ import org.openide.util.Lookup;
|
||||
*/
|
||||
public class FileSearchAction extends AbstractAction {
|
||||
|
||||
private final Long dataSourceId;
|
||||
|
||||
public FileSearchAction(String title, long dataSourceID) {
|
||||
super(title);
|
||||
dataSourceId = dataSourceID;
|
||||
}
|
||||
|
||||
public FileSearchAction(String title) {
|
||||
super(title);
|
||||
dataSourceId = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
FileSearchProvider searcher = Lookup.getDefault().lookup(FileSearchProvider.class);
|
||||
if (dataSourceId == null) {
|
||||
searcher.showDialog();
|
||||
} else {
|
||||
searcher.showDialog(dataSourceId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Copyright 2011-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -23,5 +23,8 @@ package org.sleuthkit.autopsy.directorytree;
|
||||
*/
|
||||
public interface FileSearchProvider {
|
||||
|
||||
public void showDialog(Long dataSourceID);
|
||||
|
||||
@Deprecated
|
||||
public void showDialog();
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013-2019 Basis Technology Corp.
|
||||
* Copyright 2013-2021 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.FileUtil;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
||||
import org.sleuthkit.autopsy.guiutils.JFileChooserFactory;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
|
||||
/**
|
||||
@ -52,6 +53,9 @@ public class ExtractActionHelper {
|
||||
private final Logger logger = Logger.getLogger(ExtractActionHelper.class.getName());
|
||||
private String userDefinedExportPath;
|
||||
|
||||
private final JFileChooserFactory extractFileHelper = new JFileChooserFactory();
|
||||
private final JFileChooserFactory extractFilesHelper = new JFileChooserFactory();
|
||||
|
||||
/**
|
||||
* Extract the specified collection of files with an event specified for
|
||||
* context.
|
||||
@ -89,7 +93,7 @@ public class ExtractActionHelper {
|
||||
logger.log(Level.INFO, "Exception while getting open case.", ex); //NON-NLS
|
||||
return;
|
||||
}
|
||||
JFileChooser fileChooser = new JFileChooser();
|
||||
JFileChooser fileChooser = extractFileHelper.getChooser();
|
||||
fileChooser.setCurrentDirectory(new File(getExportDirectory(openCase)));
|
||||
// If there is an attribute name, change the ":". Otherwise the extracted file will be hidden
|
||||
fileChooser.setSelectedFile(new File(FileUtil.escapeFileName(selectedFile.getName())));
|
||||
@ -117,7 +121,7 @@ public class ExtractActionHelper {
|
||||
logger.log(Level.INFO, "Exception while getting open case.", ex); //NON-NLS
|
||||
return;
|
||||
}
|
||||
JFileChooser folderChooser = new JFileChooser();
|
||||
JFileChooser folderChooser = extractFilesHelper.getChooser();
|
||||
folderChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
||||
folderChooser.setCurrentDirectory(new File(getExportDirectory(openCase)));
|
||||
if (folderChooser.showSaveDialog((Component) event.getSource()) == JFileChooser.APPROVE_OPTION) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy
|
||||
*
|
||||
* Copyright 2020 Basis Technology Corp.
|
||||
* Copyright 2020-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -54,14 +54,18 @@ public abstract class AbstractFilter {
|
||||
* @param caseDb The case database
|
||||
* @param centralRepoDb The central repo database. Can be null if the
|
||||
* filter does not require it.
|
||||
* @param context The SearchContext the search which is applying this
|
||||
* filter is being performed from.
|
||||
*
|
||||
* @return The list of results that match this filter (and any that came
|
||||
* before it)
|
||||
*
|
||||
* @throws DiscoveryException
|
||||
* @throws SearchCancellationException Thrown when the user has cancelled
|
||||
* the search.
|
||||
*/
|
||||
public List<Result> applyAlternateFilter(List<Result> currentResults, SleuthkitCase caseDb,
|
||||
CentralRepository centralRepoDb) throws DiscoveryException {
|
||||
CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy
|
||||
*
|
||||
* Copyright 2020 Basis Technology Corp.
|
||||
* Copyright 2020-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -78,10 +78,14 @@ public class DiscoveryAttributes {
|
||||
* @param caseDb The case database.
|
||||
* @param centralRepoDb The central repository database. Can be null if
|
||||
* not needed.
|
||||
* @param context The SearchContext the search which is applying
|
||||
* this filter is being performed from.
|
||||
*
|
||||
* @throws DiscoveryException
|
||||
* @throws SearchCancellationException - Thrown when the user has
|
||||
* cancelled the search.
|
||||
*/
|
||||
public void addAttributeToResults(List<Result> results, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException {
|
||||
public void addAttributeToResults(List<Result> results, SleuthkitCase caseDb, CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException {
|
||||
// Default is to do nothing
|
||||
}
|
||||
}
|
||||
@ -154,10 +158,13 @@ public class DiscoveryAttributes {
|
||||
|
||||
@Override
|
||||
public void addAttributeToResults(List<Result> results, SleuthkitCase caseDb,
|
||||
CentralRepository centralRepoDb) throws DiscoveryException {
|
||||
CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException {
|
||||
try {
|
||||
Map<String, Set<String>> domainsToCategories = getDomainsWithWebCategories(caseDb);
|
||||
Map<String, Set<String>> domainsToCategories = getDomainsWithWebCategories(caseDb, context);
|
||||
for (Result result : results) {
|
||||
if (context.searchIsCancelled()) {
|
||||
throw new SearchCancellationException("The search was cancelled while Domain Category Attribute was being added.");
|
||||
}
|
||||
if (result instanceof ResultDomain) {
|
||||
ResultDomain domain = (ResultDomain) result;
|
||||
domain.addWebCategories(domainsToCategories.get(domain.getDomain()));
|
||||
@ -172,14 +179,29 @@ public class DiscoveryAttributes {
|
||||
* Loads all TSK_WEB_CATEGORY artifacts and maps the domain attribute to
|
||||
* the category name attribute. Each ResultDomain is then parsed and
|
||||
* matched against this map of values.
|
||||
*
|
||||
* @param caseDb The case database.
|
||||
* @param context The SearchContext the search which is applying this
|
||||
* filter is being performed from.
|
||||
*
|
||||
* @return domainToCategory - A map of the domain names to the category
|
||||
* name attribute they are classified as.
|
||||
*
|
||||
* @throws TskCoreException
|
||||
* @throws InterruptedException
|
||||
* @throws SearchCancellationException - Thrown when the user has
|
||||
* cancelled the search.
|
||||
*/
|
||||
private Map<String, Set<String>> getDomainsWithWebCategories(SleuthkitCase caseDb) throws TskCoreException, InterruptedException {
|
||||
private Map<String, Set<String>> getDomainsWithWebCategories(SleuthkitCase caseDb, SearchContext context) throws TskCoreException, InterruptedException, SearchCancellationException {
|
||||
Map<String, Set<String>> domainToCategory = new HashMap<>();
|
||||
|
||||
for (BlackboardArtifact artifact : caseDb.getBlackboardArtifacts(TSK_WEB_CATEGORIZATION)) {
|
||||
if (Thread.currentThread().isInterrupted()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
if (context.searchIsCancelled()) {
|
||||
throw new SearchCancellationException("Search was cancelled while getting domains for artifact type: " + artifact.getDisplayName());
|
||||
}
|
||||
BlackboardAttribute webCategory = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME));
|
||||
BlackboardAttribute domain = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN));
|
||||
if (webCategory != null && domain != null) {
|
||||
@ -206,14 +228,16 @@ public class DiscoveryAttributes {
|
||||
|
||||
@Override
|
||||
public void addAttributeToResults(List<Result> results, SleuthkitCase caseDb,
|
||||
CentralRepository centralRepoDb) throws DiscoveryException {
|
||||
CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException {
|
||||
|
||||
// Get pairs of (object ID, keyword list name) for all files in the list of files that have
|
||||
// keyword list hits.
|
||||
String selectQuery = createSetNameClause(results, BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID(),
|
||||
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID());
|
||||
|
||||
SetKeywordListNamesCallback callback = new SetKeywordListNamesCallback(results);
|
||||
if (context.searchIsCancelled()) {
|
||||
throw new SearchCancellationException("The search was cancelled while Keyword List Attribute was being added.");
|
||||
}
|
||||
try {
|
||||
caseDb.getCaseDbAccessManager().select(selectQuery, callback);
|
||||
} catch (TskCoreException ex) {
|
||||
@ -278,8 +302,20 @@ public class DiscoveryAttributes {
|
||||
* Example: query for notable status of google.com. Result: notable With
|
||||
* this map, all domain instances that represent google.com can be updated
|
||||
* after one simple lookup.
|
||||
*
|
||||
* @param domainsBatch The list of ResultDomains to organize.
|
||||
* @param attributeType The type of correlation attribute being organized.
|
||||
* @param context The SearchContext the search which is applying this
|
||||
* filter is being performed from.
|
||||
*
|
||||
* @return resultDomainTable - A map of the normalized domain name to the
|
||||
* list of ResultDomain objects which are part of that normalized
|
||||
* domain.
|
||||
*
|
||||
* @throws SearchCancellationException - Thrown when the user has cancelled
|
||||
* the search.
|
||||
*/
|
||||
private static Map<String, List<ResultDomain>> organizeByValue(List<ResultDomain> domainsBatch, CorrelationAttributeInstance.Type attributeType) {
|
||||
private static Map<String, List<ResultDomain>> organizeByValue(List<ResultDomain> domainsBatch, CorrelationAttributeInstance.Type attributeType, SearchContext context) throws SearchCancellationException {
|
||||
final Map<String, List<ResultDomain>> resultDomainTable = new HashMap<>();
|
||||
for (ResultDomain domainInstance : domainsBatch) {
|
||||
try {
|
||||
@ -288,6 +324,9 @@ public class DiscoveryAttributes {
|
||||
final List<ResultDomain> bucket = resultDomainTable.getOrDefault(normalizedDomain, new ArrayList<>());
|
||||
bucket.add(domainInstance);
|
||||
resultDomainTable.put(normalizedDomain, bucket);
|
||||
if (context.searchIsCancelled()) {
|
||||
throw new SearchCancellationException("Search was cancelled while orgainizing domains by their normalized value.");
|
||||
}
|
||||
} catch (CorrelationAttributeNormalizationException ex) {
|
||||
logger.log(Level.INFO, String.format("Domain [%s] failed normalization, skipping...", domainInstance.getDomain()));
|
||||
}
|
||||
@ -322,39 +361,73 @@ public class DiscoveryAttributes {
|
||||
|
||||
@Override
|
||||
public void addAttributeToResults(List<Result> results, SleuthkitCase caseDb,
|
||||
CentralRepository centralRepoDb) throws DiscoveryException {
|
||||
CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException {
|
||||
|
||||
if (centralRepoDb != null) {
|
||||
processFilesWithCr(results, centralRepoDb);
|
||||
processFilesWithCr(results, centralRepoDb, context);
|
||||
}
|
||||
}
|
||||
|
||||
private void processFilesWithCr(List<Result> results, CentralRepository centralRepo) throws DiscoveryException {
|
||||
/**
|
||||
* Helper method to batch the domain results and check for notability.
|
||||
*
|
||||
* @param results The results which are being checked for previously
|
||||
* being notable in the CR.
|
||||
* @param centralRepo The central repository being used to check for
|
||||
* notability.
|
||||
* @param context The SearchContext the search which is applying
|
||||
* this filter is being performed from.
|
||||
*
|
||||
* @throws DiscoveryException
|
||||
* @throws SearchCancellationException - Thrown when the user has
|
||||
* cancelled the search.
|
||||
*/
|
||||
private void processFilesWithCr(List<Result> results, CentralRepository centralRepo, SearchContext context) throws DiscoveryException, SearchCancellationException {
|
||||
|
||||
List<ResultDomain> domainsBatch = new ArrayList<>();
|
||||
for (Result result : results) {
|
||||
if (context.searchIsCancelled()) {
|
||||
throw new SearchCancellationException("The search was cancelled while Previously Notable attribute was being calculated with the CR.");
|
||||
}
|
||||
if (result.getType() == SearchData.Type.DOMAIN) {
|
||||
domainsBatch.add((ResultDomain) result);
|
||||
if (domainsBatch.size() == DOMAIN_BATCH_SIZE) {
|
||||
queryPreviouslyNotable(domainsBatch, centralRepo);
|
||||
queryPreviouslyNotable(domainsBatch, centralRepo, context);
|
||||
domainsBatch.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
queryPreviouslyNotable(domainsBatch, centralRepo);
|
||||
queryPreviouslyNotable(domainsBatch, centralRepo, context);
|
||||
}
|
||||
|
||||
private void queryPreviouslyNotable(List<ResultDomain> domainsBatch, CentralRepository centralRepo) throws DiscoveryException {
|
||||
/**
|
||||
* Helper method to check a batch of domains for notability.
|
||||
*
|
||||
*
|
||||
* @param domainsBatch The list of ResultDomains to check for
|
||||
* notability.
|
||||
* @param centralRepo The central repository being used to check for
|
||||
* notability.
|
||||
* @param context The SearchContext the search which is applying
|
||||
* this filter is being performed from.
|
||||
*
|
||||
* @throws DiscoveryException
|
||||
* @throws SearchCancellationException - Thrown when the user has
|
||||
* cancelled the search.
|
||||
*/
|
||||
private void queryPreviouslyNotable(List<ResultDomain> domainsBatch, CentralRepository centralRepo, SearchContext context) throws DiscoveryException, SearchCancellationException {
|
||||
if (domainsBatch.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final CorrelationAttributeInstance.Type attributeType = centralRepo.getCorrelationTypeById(CorrelationAttributeInstance.DOMAIN_TYPE_ID);
|
||||
final Map<String, List<ResultDomain>> resultDomainTable = organizeByValue(domainsBatch, attributeType);
|
||||
final Map<String, List<ResultDomain>> resultDomainTable = organizeByValue(domainsBatch, attributeType, context);
|
||||
final String values = createCSV(resultDomainTable.keySet());
|
||||
|
||||
if (context.searchIsCancelled()) {
|
||||
throw new SearchCancellationException("Search was cancelled while checking for previously notable domains.");
|
||||
}
|
||||
final String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(attributeType);
|
||||
final String domainFrequencyQuery = " value AS domain_name "
|
||||
+ "FROM " + tableName + " "
|
||||
@ -421,7 +494,7 @@ public class DiscoveryAttributes {
|
||||
|
||||
@Override
|
||||
public void addAttributeToResults(List<Result> results, SleuthkitCase caseDb,
|
||||
CentralRepository centralRepoDb) throws DiscoveryException {
|
||||
CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException {
|
||||
if (centralRepoDb == null) {
|
||||
for (Result result : results) {
|
||||
if (result.getFrequency() == SearchData.Frequency.UNKNOWN && result.getKnown() == TskData.FileKnown.KNOWN) {
|
||||
@ -429,7 +502,7 @@ public class DiscoveryAttributes {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
processResultFilesForCR(results, centralRepoDb);
|
||||
processResultFilesForCR(results, centralRepoDb, context);
|
||||
}
|
||||
}
|
||||
|
||||
@ -437,16 +510,26 @@ public class DiscoveryAttributes {
|
||||
* Private helper method for adding Frequency attribute when CR is
|
||||
* enabled.
|
||||
*
|
||||
* @param files The list of ResultFiles to caluclate frequency
|
||||
* for.
|
||||
* @param centralRepoDb The central repository currently in use.
|
||||
* @param results The results which are having their frequency
|
||||
* checked.
|
||||
* @param centralRepoDb The central repository being used to check
|
||||
* frequency.
|
||||
* @param context The SearchContext the search which is applying
|
||||
* this filter is being performed from.
|
||||
*
|
||||
* @throws DiscoveryException
|
||||
* @throws SearchCancellationException - Thrown when the user has
|
||||
* cancelled the search.
|
||||
*/
|
||||
private void processResultFilesForCR(List<Result> results,
|
||||
CentralRepository centralRepoDb) throws DiscoveryException {
|
||||
CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException {
|
||||
List<ResultFile> currentFiles = new ArrayList<>();
|
||||
Set<String> hashesToLookUp = new HashSet<>();
|
||||
List<ResultDomain> domainsToQuery = new ArrayList<>();
|
||||
for (Result result : results) {
|
||||
if (context.searchIsCancelled()) {
|
||||
throw new SearchCancellationException("The search was cancelled while Frequency attribute was being calculated with the CR.");
|
||||
}
|
||||
// If frequency was already calculated, skip...
|
||||
if (result.getFrequency() == SearchData.Frequency.UNKNOWN) {
|
||||
if (result.getKnown() == TskData.FileKnown.KNOWN) {
|
||||
@ -462,7 +545,7 @@ public class DiscoveryAttributes {
|
||||
}
|
||||
|
||||
if (hashesToLookUp.size() >= BATCH_SIZE) {
|
||||
computeFrequency(hashesToLookUp, currentFiles, centralRepoDb);
|
||||
computeFrequency(hashesToLookUp, currentFiles, centralRepoDb, context);
|
||||
|
||||
hashesToLookUp.clear();
|
||||
currentFiles.clear();
|
||||
@ -470,16 +553,15 @@ public class DiscoveryAttributes {
|
||||
} else {
|
||||
domainsToQuery.add((ResultDomain) result);
|
||||
if (domainsToQuery.size() == DOMAIN_BATCH_SIZE) {
|
||||
queryDomainFrequency(domainsToQuery, centralRepoDb);
|
||||
|
||||
queryDomainFrequency(domainsToQuery, centralRepoDb, context);
|
||||
domainsToQuery.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
queryDomainFrequency(domainsToQuery, centralRepoDb);
|
||||
computeFrequency(hashesToLookUp, currentFiles, centralRepoDb);
|
||||
queryDomainFrequency(domainsToQuery, centralRepoDb, context);
|
||||
computeFrequency(hashesToLookUp, currentFiles, centralRepoDb, context);
|
||||
}
|
||||
}
|
||||
|
||||
@ -487,17 +569,22 @@ public class DiscoveryAttributes {
|
||||
* Query to get the frequency of a domain.
|
||||
*
|
||||
* @param domainsToQuery List of domains to check the frequency of.
|
||||
* @param centralRepository The central repository to query.
|
||||
* @param centralRepository The central repository being used to check
|
||||
* frequency.
|
||||
* @param context The SearchContext the search which is applying
|
||||
* this filter is being performed from.
|
||||
*
|
||||
* @throws DiscoveryException
|
||||
* @throws SearchCancellationException - Thrown when the user has cancelled
|
||||
* the search.
|
||||
*/
|
||||
private static void queryDomainFrequency(List<ResultDomain> domainsToQuery, CentralRepository centralRepository) throws DiscoveryException {
|
||||
private static void queryDomainFrequency(List<ResultDomain> domainsToQuery, CentralRepository centralRepository, SearchContext context) throws DiscoveryException, SearchCancellationException {
|
||||
if (domainsToQuery.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final CorrelationAttributeInstance.Type attributeType = centralRepository.getCorrelationTypeById(CorrelationAttributeInstance.DOMAIN_TYPE_ID);
|
||||
final Map<String, List<ResultDomain>> resultDomainTable = organizeByValue(domainsToQuery, attributeType);
|
||||
final Map<String, List<ResultDomain>> resultDomainTable = organizeByValue(domainsToQuery, attributeType, context);
|
||||
final String values = createCSV(resultDomainTable.keySet());
|
||||
final String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(attributeType);
|
||||
final String domainFrequencyQuery = " value AS domain_name, COUNT(value) AS frequency FROM"
|
||||
@ -508,8 +595,11 @@ public class DiscoveryAttributes {
|
||||
+ ")) AS foo GROUP BY value";
|
||||
|
||||
final DomainFrequencyCallback frequencyCallback = new DomainFrequencyCallback(resultDomainTable);
|
||||
centralRepository.processSelectClause(domainFrequencyQuery, frequencyCallback);
|
||||
|
||||
centralRepository.processSelectClause(domainFrequencyQuery, frequencyCallback);
|
||||
if (context.searchIsCancelled()) {
|
||||
throw new SearchCancellationException("The search was cancelled while Domain frequency was being queried with the CR.");
|
||||
}
|
||||
if (frequencyCallback.getCause() != null) {
|
||||
throw frequencyCallback.getCause();
|
||||
}
|
||||
@ -620,7 +710,7 @@ public class DiscoveryAttributes {
|
||||
|
||||
@Override
|
||||
public void addAttributeToResults(List<Result> results, SleuthkitCase caseDb,
|
||||
CentralRepository centralRepoDb) throws DiscoveryException {
|
||||
CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException {
|
||||
|
||||
// Get pairs of (object ID, hash set name) for all files in the list of files that have
|
||||
// hash set hits.
|
||||
@ -628,6 +718,9 @@ public class DiscoveryAttributes {
|
||||
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID());
|
||||
|
||||
HashSetNamesCallback callback = new HashSetNamesCallback(results);
|
||||
if (context.searchIsCancelled()) {
|
||||
throw new SearchCancellationException("The search was cancelled while Hash Hit attribute was being added.");
|
||||
}
|
||||
try {
|
||||
caseDb.getCaseDbAccessManager().select(selectQuery, callback);
|
||||
} catch (TskCoreException ex) {
|
||||
@ -695,7 +788,7 @@ public class DiscoveryAttributes {
|
||||
|
||||
@Override
|
||||
public void addAttributeToResults(List<Result> results, SleuthkitCase caseDb,
|
||||
CentralRepository centralRepoDb) throws DiscoveryException {
|
||||
CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException {
|
||||
|
||||
// Get pairs of (object ID, interesting item set name) for all files in the list of files that have
|
||||
// interesting file set hits.
|
||||
@ -703,6 +796,9 @@ public class DiscoveryAttributes {
|
||||
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID());
|
||||
|
||||
InterestingFileSetNamesCallback callback = new InterestingFileSetNamesCallback(results);
|
||||
if (context.searchIsCancelled()) {
|
||||
throw new SearchCancellationException("The search was cancelled while Interesting Item attribute was being added.");
|
||||
}
|
||||
try {
|
||||
caseDb.getCaseDbAccessManager().select(selectQuery, callback);
|
||||
} catch (TskCoreException ex) {
|
||||
@ -808,7 +904,7 @@ public class DiscoveryAttributes {
|
||||
|
||||
@Override
|
||||
public void addAttributeToResults(List<Result> results, SleuthkitCase caseDb,
|
||||
CentralRepository centralRepoDb) throws DiscoveryException {
|
||||
CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException {
|
||||
|
||||
// Get pairs of (object ID, object type name) for all files in the list of files that have
|
||||
// objects detected
|
||||
@ -816,6 +912,9 @@ public class DiscoveryAttributes {
|
||||
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION.getTypeID());
|
||||
|
||||
ObjectDetectedNamesCallback callback = new ObjectDetectedNamesCallback(results);
|
||||
if (context.searchIsCancelled()) {
|
||||
throw new SearchCancellationException("The search was cancelled while Object Detected attribute was being added.");
|
||||
}
|
||||
try {
|
||||
caseDb.getCaseDbAccessManager().select(selectQuery, callback);
|
||||
} catch (TskCoreException ex) {
|
||||
@ -884,10 +983,13 @@ public class DiscoveryAttributes {
|
||||
|
||||
@Override
|
||||
public void addAttributeToResults(List<Result> results, SleuthkitCase caseDb,
|
||||
CentralRepository centralRepoDb) throws DiscoveryException {
|
||||
CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException {
|
||||
|
||||
try {
|
||||
for (Result result : results) {
|
||||
if (context.searchIsCancelled()) {
|
||||
throw new SearchCancellationException("The search was cancelled while File Tag attribute was being added.");
|
||||
}
|
||||
if (result.getType() == SearchData.Type.DOMAIN) {
|
||||
return;
|
||||
}
|
||||
@ -995,14 +1097,20 @@ public class DiscoveryAttributes {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Computes the CR frequency of all the given hashes and updates the list of
|
||||
* files.
|
||||
*
|
||||
* @param hashesToLookUp Hashes to find the frequency of.
|
||||
* @param currentFiles List of files to update with frequencies.
|
||||
* @param centralRepoDb The central repository being used.
|
||||
* @param context The SearchContext the search which is applying this
|
||||
* filter is being performed from.
|
||||
*
|
||||
* @throws SearchCancellationException - Thrown when the user has cancelled
|
||||
* the search.
|
||||
*/
|
||||
private static void computeFrequency(Set<String> hashesToLookUp, List<ResultFile> currentFiles, CentralRepository centralRepoDb) {
|
||||
private static void computeFrequency(Set<String> hashesToLookUp, List<ResultFile> currentFiles, CentralRepository centralRepoDb, SearchContext context) throws SearchCancellationException {
|
||||
|
||||
if (hashesToLookUp.isEmpty()) {
|
||||
return;
|
||||
@ -1022,7 +1130,9 @@ public class DiscoveryAttributes {
|
||||
|
||||
FrequencyCallback callback = new FrequencyCallback(currentFiles);
|
||||
centralRepoDb.processSelectClause(selectClause, callback);
|
||||
|
||||
if (context.searchIsCancelled()) {
|
||||
throw new SearchCancellationException("The search was cancelled while Domain frequency was being queried with the CR.");
|
||||
}
|
||||
} catch (CentralRepoException ex) {
|
||||
logger.log(Level.WARNING, "Error getting frequency counts from Central Repository", ex); // NON-NLS
|
||||
}
|
||||
|
@ -59,6 +59,7 @@ public class DiscoveryKeyUtils {
|
||||
private final List<AbstractFilter> filters;
|
||||
private final SleuthkitCase sleuthkitCase;
|
||||
private final CentralRepository centralRepository;
|
||||
private final SearchContext context;
|
||||
|
||||
/**
|
||||
* Construct a new SearchKey with all information that defines a search.
|
||||
@ -70,16 +71,20 @@ public class DiscoveryKeyUtils {
|
||||
* @param sortingMethod The method to sort the results by.
|
||||
* @param sleuthkitCase The SleuthkitCase being searched.
|
||||
* @param centralRepository The Central Repository being searched.
|
||||
* @param context The SearchContext which reflects the search
|
||||
* being performed to get results for this
|
||||
* key.
|
||||
*/
|
||||
SearchKey(String userName, List<AbstractFilter> filters,
|
||||
DiscoveryAttributes.AttributeType groupAttributeType,
|
||||
Group.GroupSortingAlgorithm groupSortingType,
|
||||
ResultsSorter.SortingMethod sortingMethod,
|
||||
SleuthkitCase sleuthkitCase, CentralRepository centralRepository) {
|
||||
SleuthkitCase sleuthkitCase, CentralRepository centralRepository, SearchContext context) {
|
||||
this.groupAttributeType = groupAttributeType;
|
||||
this.groupSortingType = groupSortingType;
|
||||
this.sortingMethod = sortingMethod;
|
||||
this.filters = filters;
|
||||
this.context = context;
|
||||
|
||||
StringBuilder searchStringBuilder = new StringBuilder();
|
||||
searchStringBuilder.append(userName);
|
||||
@ -93,8 +98,8 @@ public class DiscoveryKeyUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a SearchKey without a SleuthkitCase or CentralRepositry
|
||||
* instance.
|
||||
* Construct a SearchKey without a SearchContext, SleuthkitCase or
|
||||
* CentralRepositry instance.
|
||||
*
|
||||
* @param userName The name of the user performing the search.
|
||||
* @param filters The Filters being used for the search.
|
||||
@ -107,7 +112,8 @@ public class DiscoveryKeyUtils {
|
||||
Group.GroupSortingAlgorithm groupSortingType,
|
||||
ResultsSorter.SortingMethod sortingMethod) {
|
||||
this(userName, filters, groupAttributeType, groupSortingType,
|
||||
sortingMethod, null, null);
|
||||
sortingMethod, null, null, null);
|
||||
//this constructor should only be used putting things directly into a map or getting if present since casedb, cr, and search context will be null
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -141,6 +147,23 @@ public class DiscoveryKeyUtils {
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SearchContext for the search this key is being used in.
|
||||
*
|
||||
* @return The SearchContext the search key is being used in.
|
||||
*
|
||||
* @throws DiscoveryException Thrown when the key being used has a null
|
||||
* context indicating it was not created with
|
||||
* knowledge of the case or central
|
||||
* repository databases.
|
||||
*/
|
||||
SearchContext getContext() throws DiscoveryException {
|
||||
if (context == null) {
|
||||
throw new DiscoveryException("The key in use was created without a context and does not support retrieving information from the databases.");
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the String representation of this key.
|
||||
*
|
||||
|
@ -78,24 +78,31 @@ public class DomainSearch {
|
||||
* @param caseDb The case database.
|
||||
* @param centralRepoDb The central repository database. Can be null
|
||||
* if not needed.
|
||||
* @param context The SearchContext the search is being performed from.
|
||||
*
|
||||
* @return A LinkedHashMap grouped and sorted according to the parameters.
|
||||
*
|
||||
* @throws DiscoveryException
|
||||
* @throws SearchCancellationException - Thrown when the user has cancelled
|
||||
* the search.
|
||||
*/
|
||||
public Map<GroupKey, Integer> getGroupSizes(String userName,
|
||||
List<AbstractFilter> filters,
|
||||
DiscoveryAttributes.AttributeType groupAttributeType,
|
||||
Group.GroupSortingAlgorithm groupSortingType,
|
||||
ResultsSorter.SortingMethod domainSortingMethod,
|
||||
SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException {
|
||||
SleuthkitCase caseDb, CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException {
|
||||
|
||||
final Map<GroupKey, List<Result>> searchResults = searchCache.get(
|
||||
userName, filters, groupAttributeType, groupSortingType,
|
||||
domainSortingMethod, caseDb, centralRepoDb);
|
||||
domainSortingMethod, caseDb, centralRepoDb, context);
|
||||
|
||||
// Transform the cached results into a map of group key to group size.
|
||||
final LinkedHashMap<GroupKey, Integer> groupSizes = new LinkedHashMap<>();
|
||||
for (GroupKey groupKey : searchResults.keySet()) {
|
||||
if (context.searchIsCancelled()) {
|
||||
throw new SearchCancellationException("The search was cancelled before group sizes were finished being calculated");
|
||||
}
|
||||
groupSizes.put(groupKey, searchResults.get(groupKey).size());
|
||||
}
|
||||
|
||||
@ -130,11 +137,11 @@ public class DomainSearch {
|
||||
Group.GroupSortingAlgorithm groupSortingType,
|
||||
ResultsSorter.SortingMethod domainSortingMethod,
|
||||
GroupKey groupKey, int startingEntry, int numberOfEntries,
|
||||
SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException {
|
||||
SleuthkitCase caseDb, CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException {
|
||||
|
||||
final Map<GroupKey, List<Result>> searchResults = searchCache.get(
|
||||
userName, filters, groupAttributeType, groupSortingType,
|
||||
domainSortingMethod, caseDb, centralRepoDb);
|
||||
domainSortingMethod, caseDb, centralRepoDb, context);
|
||||
final List<Result> domainsInGroup = searchResults.get(groupKey);
|
||||
final List<Result> page = new ArrayList<>();
|
||||
for (int i = startingEntry; (i < startingEntry + numberOfEntries)
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020 Basis Technology Corp.
|
||||
* Copyright 2020-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -55,20 +55,24 @@ class DomainSearchCache {
|
||||
* @param caseDb The case database.
|
||||
* @param centralRepoDb The central repository database. Can be null if
|
||||
* not needed.
|
||||
* @param context The SearchContext the search is being performed
|
||||
* from.
|
||||
*
|
||||
* @return Domain search results matching the given parameters.
|
||||
*
|
||||
* @throws DiscoveryException
|
||||
* @throws SearchCancellationException - Thrown when the user has cancelled
|
||||
* the search.
|
||||
*/
|
||||
Map<GroupKey, List<Result>> get(String userName,
|
||||
List<AbstractFilter> filters,
|
||||
DiscoveryAttributes.AttributeType groupAttributeType,
|
||||
Group.GroupSortingAlgorithm groupSortingType,
|
||||
ResultsSorter.SortingMethod domainSortingMethod,
|
||||
SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException {
|
||||
SleuthkitCase caseDb, CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException {
|
||||
try {
|
||||
final SearchKey searchKey = new SearchKey(userName, filters, groupAttributeType,
|
||||
groupSortingType, domainSortingMethod, caseDb, centralRepoDb);
|
||||
groupSortingType, domainSortingMethod, caseDb, centralRepoDb, context);
|
||||
return cache.get(searchKey);
|
||||
} catch (ExecutionException ex) {
|
||||
throw new DiscoveryException("Error fetching results from cache", ex.getCause());
|
||||
|
@ -73,7 +73,7 @@ class DomainSearchCacheLoader extends CacheLoader<SearchKey, Map<GroupKey, List<
|
||||
throw new InterruptedException();
|
||||
}
|
||||
attr.addAttributeToResults(domainResults,
|
||||
key.getSleuthkitCase(), key.getCentralRepository());
|
||||
key.getSleuthkitCase(), key.getCentralRepository(), key.getContext());
|
||||
}
|
||||
// Apply secondary in memory filters
|
||||
for (AbstractFilter filter : key.getFilters()) {
|
||||
@ -81,7 +81,7 @@ class DomainSearchCacheLoader extends CacheLoader<SearchKey, Map<GroupKey, List<
|
||||
throw new InterruptedException();
|
||||
}
|
||||
if (filter.useAlternateFilter()) {
|
||||
domainResults = filter.applyAlternateFilter(domainResults, key.getSleuthkitCase(), key.getCentralRepository());
|
||||
domainResults = filter.applyAlternateFilter(domainResults, key.getSleuthkitCase(), key.getCentralRepository(), key.getContext());
|
||||
}
|
||||
}
|
||||
// Sort the ResultDomains by the requested criteria.
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2019-2020 Basis Technology Corp.
|
||||
* Copyright 2019-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -62,17 +62,21 @@ public class FileSearch {
|
||||
* @param caseDb The case database
|
||||
* @param centralRepoDb The central repository database. Can be null if
|
||||
* not needed.
|
||||
* @param context The SearchContext the search is being performed
|
||||
* from.
|
||||
*
|
||||
* @return The raw search results
|
||||
*
|
||||
* @throws DiscoveryException
|
||||
* @throws SearchCancellationException - Thrown when the user has cancelled
|
||||
* the search.
|
||||
*/
|
||||
static SearchResults runFileSearchDebug(String userName,
|
||||
List<AbstractFilter> filters,
|
||||
AttributeType groupAttributeType,
|
||||
Group.GroupSortingAlgorithm groupSortingType,
|
||||
ResultsSorter.SortingMethod fileSortingMethod,
|
||||
SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException {
|
||||
SleuthkitCase caseDb, CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException {
|
||||
// Make a list of attributes that we want to add values for. This ensures the
|
||||
// ResultFile objects will have all needed fields set when it's time to group
|
||||
// and sort them. For example, if we're grouping by central repo frequency, we need
|
||||
@ -82,10 +86,10 @@ public class FileSearch {
|
||||
attributesNeededForGroupingOrSorting.addAll(fileSortingMethod.getRequiredAttributes());
|
||||
|
||||
// Run the queries for each filter
|
||||
List<Result> results = SearchFiltering.runQueries(filters, caseDb, centralRepoDb);
|
||||
List<Result> results = SearchFiltering.runQueries(filters, caseDb, centralRepoDb, context);
|
||||
|
||||
// Add the data to resultFiles for any attributes needed for sorting and grouping
|
||||
addAttributes(attributesNeededForGroupingOrSorting, results, caseDb, centralRepoDb);
|
||||
addAttributes(attributesNeededForGroupingOrSorting, results, caseDb, centralRepoDb, context);
|
||||
|
||||
// Collect everything in the search results
|
||||
SearchResults searchResults = new SearchResults(groupSortingType, groupAttributeType, fileSortingMethod);
|
||||
@ -114,21 +118,28 @@ public class FileSearch {
|
||||
* @param caseDb The case database
|
||||
* @param centralRepoDb The central repository database. Can be null if
|
||||
* not needed.
|
||||
* @param context The SearchContext the search is being performed
|
||||
* from.
|
||||
*
|
||||
* @return A LinkedHashMap grouped and sorted according to the parameters
|
||||
*
|
||||
* @throws DiscoveryException
|
||||
* @throws SearchCancellationException - Thrown when the user has cancelled
|
||||
* the search.
|
||||
*/
|
||||
public static Map<GroupKey, Integer> getGroupSizes(String userName,
|
||||
List<AbstractFilter> filters,
|
||||
AttributeType groupAttributeType,
|
||||
Group.GroupSortingAlgorithm groupSortingType,
|
||||
ResultsSorter.SortingMethod fileSortingMethod,
|
||||
SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException {
|
||||
SleuthkitCase caseDb, CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException {
|
||||
Map<GroupKey, List<Result>> searchResults = runFileSearch(userName, filters,
|
||||
groupAttributeType, groupSortingType, fileSortingMethod, caseDb, centralRepoDb);
|
||||
groupAttributeType, groupSortingType, fileSortingMethod, caseDb, centralRepoDb, context);
|
||||
LinkedHashMap<GroupKey, Integer> groupSizes = new LinkedHashMap<>();
|
||||
for (GroupKey groupKey : searchResults.keySet()) {
|
||||
if (context.searchIsCancelled()) {
|
||||
throw new SearchCancellationException("The search was cancelled before group sizes were finished being calculated");
|
||||
}
|
||||
groupSizes.put(groupKey, searchResults.get(groupKey).size());
|
||||
}
|
||||
return groupSizes;
|
||||
@ -151,10 +162,14 @@ public class FileSearch {
|
||||
* @param caseDb The case database
|
||||
* @param centralRepoDb The central repository database. Can be null if
|
||||
* not needed.
|
||||
* @param context The SearchContext the search is being performed
|
||||
* from.
|
||||
*
|
||||
* @return A LinkedHashMap grouped and sorted according to the parameters
|
||||
*
|
||||
* @throws DiscoveryException
|
||||
* @throws SearchCancellationException - Thrown when the user has cancelled
|
||||
* the search.
|
||||
*/
|
||||
public static List<Result> getFilesInGroup(String userName,
|
||||
List<AbstractFilter> filters,
|
||||
@ -164,7 +179,7 @@ public class FileSearch {
|
||||
GroupKey groupKey,
|
||||
int startingEntry,
|
||||
int numberOfEntries,
|
||||
SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException {
|
||||
SleuthkitCase caseDb, CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException {
|
||||
//the group should be in the cache at this point
|
||||
List<Result> filesInGroup = null;
|
||||
SearchKey searchKey = new SearchKey(userName, filters, groupAttributeType, groupSortingType, fileSortingMethod);
|
||||
@ -178,7 +193,7 @@ public class FileSearch {
|
||||
List<Result> page = new ArrayList<>();
|
||||
if (filesInGroup == null) {
|
||||
logger.log(Level.INFO, "Group {0} was not cached, performing search to cache all groups again", groupKey);
|
||||
runFileSearch(userName, filters, groupAttributeType, groupSortingType, fileSortingMethod, caseDb, centralRepoDb);
|
||||
runFileSearch(userName, filters, groupAttributeType, groupSortingType, fileSortingMethod, caseDb, centralRepoDb, context);
|
||||
synchronized (searchCache) {
|
||||
resultsMap = searchCache.getIfPresent(searchKey.getKeyString());
|
||||
}
|
||||
@ -218,7 +233,6 @@ public class FileSearch {
|
||||
TextSummarizer localSummarizer;
|
||||
synchronized (searchCache) {
|
||||
localSummarizer = SummaryHelpers.getLocalSummarizer();
|
||||
|
||||
}
|
||||
if (localSummarizer != null) {
|
||||
try {
|
||||
@ -247,17 +261,21 @@ public class FileSearch {
|
||||
* @param caseDb The case database
|
||||
* @param centralRepoDb The central repository database. Can be null if
|
||||
* not needed.
|
||||
* @param context The SearchContext the search is being performed
|
||||
* from.
|
||||
*
|
||||
* @return A LinkedHashMap grouped and sorted according to the parameters
|
||||
*
|
||||
* @throws DiscoveryException
|
||||
* @throws SearchCancellationException - Thrown when the user has cancelled
|
||||
* the search.
|
||||
*/
|
||||
private static Map<GroupKey, List<Result>> runFileSearch(String userName,
|
||||
public static Map<GroupKey, List<Result>> runFileSearch(String userName,
|
||||
List<AbstractFilter> filters,
|
||||
AttributeType groupAttributeType,
|
||||
Group.GroupSortingAlgorithm groupSortingType,
|
||||
ResultsSorter.SortingMethod fileSortingMethod,
|
||||
SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException {
|
||||
SleuthkitCase caseDb, CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException {
|
||||
|
||||
// Make a list of attributes that we want to add values for. This ensures the
|
||||
// ResultFile objects will have all needed fields set when it's time to group
|
||||
@ -268,10 +286,10 @@ public class FileSearch {
|
||||
attributesNeededForGroupingOrSorting.addAll(fileSortingMethod.getRequiredAttributes());
|
||||
|
||||
// Run the queries for each filter
|
||||
List<Result> results = SearchFiltering.runQueries(filters, caseDb, centralRepoDb);
|
||||
List<Result> results = SearchFiltering.runQueries(filters, caseDb, centralRepoDb, context);
|
||||
|
||||
// Add the data to resultFiles for any attributes needed for sorting and grouping
|
||||
addAttributes(attributesNeededForGroupingOrSorting, results, caseDb, centralRepoDb);
|
||||
addAttributes(attributesNeededForGroupingOrSorting, results, caseDb, centralRepoDb, context);
|
||||
|
||||
// Collect everything in the search results
|
||||
SearchResults searchResults = new SearchResults(groupSortingType, groupAttributeType, fileSortingMethod);
|
||||
@ -295,13 +313,17 @@ public class FileSearch {
|
||||
* @param caseDb The case database
|
||||
* @param centralRepoDb The central repository database. Can be null if not
|
||||
* needed.
|
||||
* @param context The SearchContext the search is being performed
|
||||
* from.
|
||||
*
|
||||
* @throws DiscoveryException
|
||||
* @throws SearchCancellationException - Thrown when the user has cancelled
|
||||
* the search.
|
||||
*/
|
||||
private static void addAttributes(List<AttributeType> attrs, List<Result> results, SleuthkitCase caseDb, CentralRepository centralRepoDb)
|
||||
throws DiscoveryException {
|
||||
private static void addAttributes(List<AttributeType> attrs, List<Result> results, SleuthkitCase caseDb, CentralRepository centralRepoDb, SearchContext context)
|
||||
throws DiscoveryException, SearchCancellationException {
|
||||
for (AttributeType attr : attrs) {
|
||||
attr.addAttributeToResults(results, caseDb, centralRepoDb);
|
||||
attr.addAttributeToResults(results, caseDb, centralRepoDb, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Autopsy
|
||||
*
|
||||
* Copyright 2021 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.discovery.search;
|
||||
|
||||
import java.util.concurrent.CancellationException;
|
||||
|
||||
/**
|
||||
* Exception to be thrown when the search has been intentionally cancelled to
|
||||
* provide information on where the code was when the cancellation took place.
|
||||
*/
|
||||
public class SearchCancellationException extends CancellationException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Construct a new SearchCancellationException with the specified message.
|
||||
*
|
||||
* @param message The text to use as the message for the exception.
|
||||
*/
|
||||
SearchCancellationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
* Autopsy
|
||||
*
|
||||
* Copyright 2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
@ -16,17 +16,18 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datasourcesummary.uiutils;
|
||||
package org.sleuthkit.autopsy.discovery.search;
|
||||
|
||||
/**
|
||||
* Basic interface for a cell model.
|
||||
* Interface for providing feedback on if a search has been cancelled.
|
||||
*
|
||||
*/
|
||||
public interface ExcelCellModel extends CellModel {
|
||||
public interface SearchContext {
|
||||
|
||||
/**
|
||||
* @return The format string to be used with Apache POI during excel
|
||||
* export or null if none necessary.
|
||||
* Returns true if the search has been cancelled, false otherwise.
|
||||
*
|
||||
* @return True if the search has been cancelled, false otherwise.
|
||||
*/
|
||||
String getExcelFormatString();
|
||||
|
||||
boolean searchIsCancelled();
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2019-2020 Basis Technology Corp.
|
||||
* Copyright 2019-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -60,10 +60,16 @@ public class SearchFiltering {
|
||||
* @param caseDb The case database.
|
||||
* @param centralRepoDb The central repo. Can be null as long as no filters
|
||||
* need it.
|
||||
* @param context The SearchContext the search is being performed
|
||||
* from.
|
||||
*
|
||||
* @return List of Results from the search performed.
|
||||
*
|
||||
* @throws DiscoveryException
|
||||
* @throws SearchCancellationException - Thrown when the user has cancelled
|
||||
* the search.
|
||||
*/
|
||||
static List<Result> runQueries(List<AbstractFilter> filters, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException {
|
||||
static List<Result> runQueries(List<AbstractFilter> filters, SleuthkitCase caseDb, CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException {
|
||||
if (caseDb == null) {
|
||||
throw new DiscoveryException("Case DB parameter is null"); // NON-NLS
|
||||
}
|
||||
@ -82,8 +88,11 @@ public class SearchFiltering {
|
||||
// The file search filter is required, so this should never be empty.
|
||||
throw new DiscoveryException("Selected filters do not include a case database query");
|
||||
}
|
||||
if (context.searchIsCancelled()) {
|
||||
throw new SearchCancellationException("The search was cancelled before result list could be retrieved.");
|
||||
}
|
||||
try {
|
||||
return getResultList(filters, combinedQuery, caseDb, centralRepoDb);
|
||||
return getResultList(filters, combinedQuery, caseDb, centralRepoDb, context);
|
||||
} catch (TskCoreException ex) {
|
||||
throw new DiscoveryException("Error querying case database", ex); // NON-NLS
|
||||
}
|
||||
@ -97,17 +106,23 @@ public class SearchFiltering {
|
||||
* @param caseDb The case database.
|
||||
* @param centralRepoDb The central repo. Can be null as long as no filters
|
||||
* need it.
|
||||
* @param context The SearchContext the search is being performed
|
||||
* from.
|
||||
*
|
||||
* @return An ArrayList of Results returned by the query.
|
||||
*
|
||||
* @throws TskCoreException
|
||||
* @throws DiscoveryException
|
||||
* @throws SearchCancellationException - Thrown when the user has cancelled
|
||||
* the search.
|
||||
*/
|
||||
private static List<Result> getResultList(List<AbstractFilter> filters, String combinedQuery, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws TskCoreException, DiscoveryException {
|
||||
private static List<Result> getResultList(List<AbstractFilter> filters, String combinedQuery, SleuthkitCase caseDb, CentralRepository centralRepoDb, SearchContext context) throws TskCoreException, DiscoveryException, SearchCancellationException {
|
||||
// Get all matching abstract files
|
||||
List<Result> resultList = new ArrayList<>();
|
||||
List<AbstractFile> sqlResults = caseDb.findAllFilesWhere(combinedQuery);
|
||||
|
||||
if (context.searchIsCancelled()) {
|
||||
throw new SearchCancellationException("The search was cancelled while the case database query was being performed.");
|
||||
}
|
||||
// If there are no results, return now
|
||||
if (sqlResults.isEmpty()) {
|
||||
return resultList;
|
||||
@ -120,8 +135,11 @@ public class SearchFiltering {
|
||||
|
||||
// Now run any non-SQL filters.
|
||||
for (AbstractFilter filter : filters) {
|
||||
if (context.searchIsCancelled()) {
|
||||
throw new SearchCancellationException("The search was cancelled while alternate filters were being applied.");
|
||||
}
|
||||
if (filter.useAlternateFilter()) {
|
||||
resultList = filter.applyAlternateFilter(resultList, caseDb, centralRepoDb);
|
||||
resultList = filter.applyAlternateFilter(resultList, caseDb, centralRepoDb, context);
|
||||
}
|
||||
// There are no matches for the filters run so far, so return
|
||||
if (resultList.isEmpty()) {
|
||||
@ -243,7 +261,8 @@ public class SearchFiltering {
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by backend domain search code to query for additional artifact types.
|
||||
* Used by backend domain search code to query for additional artifact
|
||||
* types.
|
||||
*/
|
||||
String getWhereClause(List<ARTIFACT_TYPE> nonVisibleArtifactTypesToInclude) {
|
||||
StringJoiner joiner = joinStandardArtifactTypes();
|
||||
@ -674,14 +693,17 @@ public class SearchFiltering {
|
||||
|
||||
@Override
|
||||
public List<Result> applyAlternateFilter(List<Result> currentResults, SleuthkitCase caseDb,
|
||||
CentralRepository centralRepoDb) throws DiscoveryException {
|
||||
CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException {
|
||||
// Set the frequency for each file
|
||||
DiscoveryAttributes.FrequencyAttribute freqAttr = new DiscoveryAttributes.FrequencyAttribute();
|
||||
freqAttr.addAttributeToResults(currentResults, caseDb, centralRepoDb);
|
||||
freqAttr.addAttributeToResults(currentResults, caseDb, centralRepoDb, context);
|
||||
|
||||
// If the frequency matches the filter, add the file to the results
|
||||
List<Result> frequencyResults = new ArrayList<>();
|
||||
for (Result file : currentResults) {
|
||||
if (context.searchIsCancelled()) {
|
||||
throw new SearchCancellationException("The search was cancelled while Frequency alternate filter was being applied.");
|
||||
}
|
||||
if (frequencies.contains(file.getFrequency())) {
|
||||
frequencyResults.add(file);
|
||||
}
|
||||
@ -723,9 +745,12 @@ public class SearchFiltering {
|
||||
|
||||
@Override
|
||||
public List<Result> applyAlternateFilter(List<Result> currentResults, SleuthkitCase caseDb,
|
||||
CentralRepository centralRepoDb) throws DiscoveryException {
|
||||
CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException {
|
||||
List<Result> filteredResults = new ArrayList<>();
|
||||
for (Result result : currentResults) {
|
||||
if (context.searchIsCancelled()) {
|
||||
throw new SearchCancellationException("The search was cancelled while Known Account Type alternate filter was being applied.");
|
||||
}
|
||||
if (result instanceof ResultDomain) {
|
||||
ResultDomain domain = (ResultDomain) result;
|
||||
if (domain.hasKnownAccountType()) {
|
||||
@ -765,11 +790,14 @@ public class SearchFiltering {
|
||||
|
||||
@Override
|
||||
public List<Result> applyAlternateFilter(List<Result> currentResults, SleuthkitCase caseDb,
|
||||
CentralRepository centralRepoDb) throws DiscoveryException {
|
||||
CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException {
|
||||
DiscoveryAttributes.PreviouslyNotableAttribute previouslyNotableAttr = new DiscoveryAttributes.PreviouslyNotableAttribute();
|
||||
previouslyNotableAttr.addAttributeToResults(currentResults, caseDb, centralRepoDb);
|
||||
previouslyNotableAttr.addAttributeToResults(currentResults, caseDb, centralRepoDb, context);
|
||||
List<Result> filteredResults = new ArrayList<>();
|
||||
for (Result file : currentResults) {
|
||||
if (context.searchIsCancelled()) {
|
||||
throw new SearchCancellationException("The search was cancelled while Previously Notable alternate filter was being applied.");
|
||||
}
|
||||
if (file.getPreviouslyNotableInCR() == SearchData.PreviouslyNotable.PREVIOUSLY_NOTABLE) {
|
||||
filteredResults.add(file);
|
||||
}
|
||||
@ -1068,7 +1096,7 @@ public class SearchFiltering {
|
||||
|
||||
@Override
|
||||
public List<Result> applyAlternateFilter(List<Result> currentResults, SleuthkitCase caseDb,
|
||||
CentralRepository centralRepoDb) throws DiscoveryException {
|
||||
CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException {
|
||||
|
||||
if (centralRepoDb == null) {
|
||||
throw new DiscoveryException("Can not run Previously Notable filter with null Central Repository DB"); // NON-NLS
|
||||
@ -1087,6 +1115,9 @@ public class SearchFiltering {
|
||||
CorrelationAttributeInstance.Type type = CorrelationAttributeInstance.getDefaultCorrelationTypes().get(CorrelationAttributeInstance.FILES_TYPE_ID);
|
||||
|
||||
for (Result result : currentResults) {
|
||||
if (context.searchIsCancelled()) {
|
||||
throw new SearchCancellationException("The search was cancelled while Notable alternate filter was being applied.");
|
||||
}
|
||||
ResultFile file = (ResultFile) result;
|
||||
if (result.getType() == SearchData.Type.DOMAIN) {
|
||||
break;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy
|
||||
*
|
||||
* Copyright 2020 Basis Technology Corp.
|
||||
* Copyright 2020-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -31,7 +31,6 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.SwingUtilities;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.openide.windows.WindowManager;
|
||||
@ -574,7 +573,7 @@ final class DiscoveryDialog extends javax.swing.JDialog {
|
||||
}
|
||||
|
||||
private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchButtonActionPerformed
|
||||
// Get the selected filters
|
||||
setVisible(false); //set visible used here instead of dispose incase dispose code changes
|
||||
final DiscoveryTopComponent tc = DiscoveryTopComponent.getTopComponent();
|
||||
if (tc == null) {
|
||||
setValid("No Top Component Found");
|
||||
@ -584,6 +583,7 @@ final class DiscoveryDialog extends javax.swing.JDialog {
|
||||
tc.open();
|
||||
}
|
||||
tc.resetTopComponent();
|
||||
// Get the selected filters
|
||||
List<AbstractFilter> filters;
|
||||
if (videosButton.isSelected()) {
|
||||
filters = videoFilterPanel.getFilters();
|
||||
@ -617,7 +617,6 @@ final class DiscoveryDialog extends javax.swing.JDialog {
|
||||
}
|
||||
searchWorker = new SearchWorker(centralRepoDb, type, filters, groupingAttr, groupSortAlgorithm, fileSort);
|
||||
searchWorker.execute();
|
||||
dispose();
|
||||
tc.toFront();
|
||||
tc.requestActive();
|
||||
}//GEN-LAST:event_searchButtonActionPerformed
|
||||
@ -651,6 +650,7 @@ final class DiscoveryDialog extends javax.swing.JDialog {
|
||||
void cancelSearch() {
|
||||
if (searchWorker != null) {
|
||||
searchWorker.cancel(true);
|
||||
searchWorker = null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -750,7 +750,6 @@ final class DiscoveryDialog extends javax.swing.JDialog {
|
||||
|| eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) {
|
||||
shouldUpdate = shouldUpdateFilters(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID(), eventData, interestingItems);
|
||||
}
|
||||
|
||||
}
|
||||
} catch (NoCurrentCaseException notUsed) {
|
||||
// Case is closed, do nothing.
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy
|
||||
*
|
||||
* Copyright 2019-2020 Basis Technology Corp.
|
||||
* Copyright 2019-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -260,7 +260,6 @@ public final class DiscoveryTopComponent extends TopComponent {
|
||||
private void newSearchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newSearchButtonActionPerformed
|
||||
close();
|
||||
final DiscoveryDialog discDialog = DiscoveryDialog.getDiscoveryDialogInstance();
|
||||
discDialog.cancelSearch();
|
||||
discDialog.setVisible(true);
|
||||
discDialog.validateDialog();
|
||||
}//GEN-LAST:event_newSearchButtonActionPerformed
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy
|
||||
*
|
||||
* Copyright 2019 Basis Technology Corp.
|
||||
* Copyright 2019-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -36,6 +36,8 @@ import org.sleuthkit.autopsy.discovery.search.DiscoveryException;
|
||||
import org.sleuthkit.autopsy.discovery.search.DomainSearch;
|
||||
import org.sleuthkit.autopsy.discovery.search.ResultsSorter;
|
||||
import org.sleuthkit.autopsy.discovery.search.Result;
|
||||
import org.sleuthkit.autopsy.discovery.search.SearchCancellationException;
|
||||
import org.sleuthkit.autopsy.discovery.search.SearchContext;
|
||||
|
||||
/**
|
||||
* SwingWorker to retrieve the contents of a page.
|
||||
@ -87,7 +89,7 @@ final class PageWorker extends SwingWorker<Void, Void> {
|
||||
|
||||
@Override
|
||||
protected Void doInBackground() throws Exception {
|
||||
|
||||
SearchContext context = new SwingWorkerSearchContext(this);
|
||||
try {
|
||||
// Run the search
|
||||
if (resultType == SearchData.Type.DOMAIN) {
|
||||
@ -96,17 +98,22 @@ final class PageWorker extends SwingWorker<Void, Void> {
|
||||
groupingAttribute,
|
||||
groupSort,
|
||||
fileSortMethod, groupKey, startingEntry, pageSize,
|
||||
Case.getCurrentCase().getSleuthkitCase(), centralRepo));
|
||||
Case.getCurrentCase().getSleuthkitCase(), centralRepo, context));
|
||||
} else {
|
||||
results.addAll(FileSearch.getFilesInGroup(System.getProperty(USER_NAME_PROPERTY), searchfilters,
|
||||
groupingAttribute,
|
||||
groupSort,
|
||||
fileSortMethod, groupKey, startingEntry, pageSize,
|
||||
Case.getCurrentCase().getSleuthkitCase(), centralRepo));
|
||||
Case.getCurrentCase().getSleuthkitCase(), centralRepo, context));
|
||||
}
|
||||
} catch (DiscoveryException ex) {
|
||||
logger.log(Level.SEVERE, "Error running file search test", ex);
|
||||
cancel(true);
|
||||
} catch (SearchCancellationException ex) {
|
||||
//The user does not explicitly have a way to cancel the loading of a page
|
||||
//but they could have cancelled the search during the loading of the first page
|
||||
//So this may or may not be an issue depending on when this occurred.
|
||||
logger.log(Level.WARNING, "Search was cancelled while retrieving data for results page with starting entry: " + startingEntry, ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy
|
||||
*
|
||||
* Copyright 2019 Basis Technology Corp.
|
||||
* Copyright 2019-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -35,6 +35,8 @@ import org.sleuthkit.autopsy.discovery.search.FileSearch;
|
||||
import org.sleuthkit.autopsy.discovery.search.DiscoveryException;
|
||||
import org.sleuthkit.autopsy.discovery.search.DomainSearch;
|
||||
import org.sleuthkit.autopsy.discovery.search.ResultsSorter;
|
||||
import org.sleuthkit.autopsy.discovery.search.SearchCancellationException;
|
||||
import org.sleuthkit.autopsy.discovery.search.SearchContext;
|
||||
import org.sleuthkit.autopsy.discovery.search.SearchData;
|
||||
|
||||
/**
|
||||
@ -75,23 +77,28 @@ final class SearchWorker extends SwingWorker<Void, Void> {
|
||||
protected Void doInBackground() throws Exception {
|
||||
try {
|
||||
// Run the search
|
||||
SearchContext context = new SwingWorkerSearchContext(this);
|
||||
if (searchType == SearchData.Type.DOMAIN) {
|
||||
DomainSearch domainSearch = new DomainSearch();
|
||||
results.putAll(domainSearch.getGroupSizes(System.getProperty(USER_NAME_PROPERTY), filters,
|
||||
groupingAttr,
|
||||
groupSortAlgorithm,
|
||||
fileSort,
|
||||
Case.getCurrentCase().getSleuthkitCase(), centralRepoDb));
|
||||
Case.getCurrentCase().getSleuthkitCase(), centralRepoDb, context));
|
||||
} else {
|
||||
results.putAll(FileSearch.getGroupSizes(System.getProperty(USER_NAME_PROPERTY), filters,
|
||||
groupingAttr,
|
||||
groupSortAlgorithm,
|
||||
fileSort,
|
||||
Case.getCurrentCase().getSleuthkitCase(), centralRepoDb));
|
||||
Case.getCurrentCase().getSleuthkitCase(), centralRepoDb, context));
|
||||
}
|
||||
} catch (DiscoveryException ex) {
|
||||
logger.log(Level.SEVERE, "Error running file search test", ex);
|
||||
logger.log(Level.SEVERE, "Error running file search test.", ex);
|
||||
cancel(true);
|
||||
} catch (SearchCancellationException ex) {
|
||||
//search cancellation exceptions should indicate that the user chose to cancell this search
|
||||
//so would not be a problem but we might be curious what was being done when it was cancelled
|
||||
logger.log(Level.INFO, "Discovery search was cancelled.", ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Autopsy
|
||||
*
|
||||
* Copyright 2021 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.discovery.ui;
|
||||
|
||||
import javax.swing.SwingWorker;
|
||||
import org.sleuthkit.autopsy.discovery.search.SearchContext;
|
||||
|
||||
/**
|
||||
* Implementation of SearchContext for searches being performed in the
|
||||
* background thread of a SwingWorker.
|
||||
*/
|
||||
class SwingWorkerSearchContext implements SearchContext {
|
||||
|
||||
private final SwingWorker<Void, Void> searchWorker;
|
||||
|
||||
/**
|
||||
* Construct a new SwingWorkerSearchContext.
|
||||
*
|
||||
* @param worker The SwingWorker the search is being performed in.
|
||||
*/
|
||||
SwingWorkerSearchContext(SwingWorker<Void, Void> worker) {
|
||||
searchWorker = worker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean searchIsCancelled() {
|
||||
return searchWorker.isCancelled();
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user