mirror of
https://github.com/elisspace/autopsy.git
synced 2026-09-30 14:29:51 +00:00
merge
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
package org.sleuthkit.autopsy.casemodule;
|
||||
|
||||
import java.util.List;
|
||||
import org.sleuthkit.autopsy.ingest.IngestJob;
|
||||
import org.sleuthkit.autopsy.ingest.IngestStream;
|
||||
import org.sleuthkit.autopsy.ingest.IngestStreamClosedException;
|
||||
|
||||
@@ -35,6 +36,11 @@ class DefaultIngestStream implements IngestStream {
|
||||
public void addFiles(List<Long> fileObjectIds) throws IngestStreamClosedException {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public IngestJob getIngestJob() {
|
||||
throw new UnsupportedOperationException("DefaultIngestStream has no associated IngestJob");
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isClosed() {
|
||||
|
||||
@@ -464,6 +464,42 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour
|
||||
|
||||
doAddImageProcess(deviceId, dataSourcePath.toString(), sectorSize, timeZone, ignoreFatOrphanFiles, null, null, null, progressMonitor, callBack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IngestStream processWithIngestStream(String deviceId, Path dataSourcePath, IngestJobSettings settings, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack) {
|
||||
this.deviceId = deviceId;
|
||||
this.imagePath = dataSourcePath.toString();
|
||||
this.sectorSize = 0;
|
||||
this.timeZone = Calendar.getInstance().getTimeZone().getID();
|
||||
this.ignoreFatOrphanFiles = false;
|
||||
setDataSourceOptionsCalled = true;
|
||||
|
||||
// Set up the data source before creating the ingest stream
|
||||
try {
|
||||
image = SleuthkitJNI.addImageToDatabase(Case.getCurrentCase().getSleuthkitCase(),
|
||||
new String[]{imagePath}, sectorSize, timeZone, md5, sha1, sha256, deviceId);
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error adding data source with path " + imagePath + " to database", ex);
|
||||
final List<String> errors = new ArrayList<>();
|
||||
errors.add(ex.getMessage());
|
||||
callBack.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errors, new ArrayList<>());
|
||||
return null;
|
||||
}
|
||||
|
||||
// Now initialize the ingest stream
|
||||
try {
|
||||
ingestStream = IngestManager.getInstance().openIngestStream(image, settings);
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error starting ingest modules", ex);
|
||||
final List<String> errors = new ArrayList<>();
|
||||
errors.add(ex.getMessage());
|
||||
callBack.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errors, new ArrayList<>());
|
||||
return null;
|
||||
}
|
||||
|
||||
doAddImageProcess(deviceId, dataSourcePath.toString(), sectorSize, timeZone, ignoreFatOrphanFiles, null, null, null, progressMonitor, callBack);
|
||||
return ingestStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the configuration of the data source processor without using the
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2019 Basis Technology Corp.
|
||||
* Copyright 2018-2020 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -97,68 +97,64 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
* Image viewer part of the Media View layered pane. Uses JavaFX to display the
|
||||
* image.
|
||||
*/
|
||||
@NbBundle.Messages({"MediaViewImagePanel.externalViewerButton.text=Open in External Viewer Ctrl+E",
|
||||
@NbBundle.Messages({
|
||||
"MediaViewImagePanel.externalViewerButton.text=Open in External Viewer Ctrl+E",
|
||||
"MediaViewImagePanel.errorLabel.text=Could not load file into Media View.",
|
||||
"MediaViewImagePanel.errorLabel.OOMText=Could not load file into Media View: insufficent memory."})
|
||||
"MediaViewImagePanel.errorLabel.OOMText=Could not load file into Media View: insufficent memory."
|
||||
})
|
||||
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
||||
class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPanel {
|
||||
|
||||
private static final Image EXTERNAL = new Image(MediaViewImagePanel.class.getResource("/org/sleuthkit/autopsy/images/external.png").toExternalForm());
|
||||
private final static Logger LOGGER = Logger.getLogger(MediaViewImagePanel.class.getName());
|
||||
|
||||
private final boolean fxInited;
|
||||
|
||||
private JFXPanel fxPanel;
|
||||
private AbstractFile file;
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger logger = Logger.getLogger(MediaViewImagePanel.class.getName());
|
||||
private static final double[] ZOOM_STEPS = {
|
||||
0.0625, 0.125, 0.25, 0.375, 0.5, 0.75,
|
||||
1, 1.5, 2, 2.5, 3, 4, 5, 6, 8, 10};
|
||||
private static final double MIN_ZOOM_RATIO = 0.0625; // 6.25%
|
||||
private static final double MAX_ZOOM_RATIO = 10.0; // 1000%
|
||||
private static final Image externalImage = new Image(MediaViewImagePanel.class.getResource("/org/sleuthkit/autopsy/images/external.png").toExternalForm());
|
||||
private static final SortedSet<String> supportedMimes = ImageUtils.getSupportedImageMimeTypes();
|
||||
private static final List<String> supportedExtensions = ImageUtils.getSupportedImageExtensions().stream()
|
||||
.map("."::concat) //NOI18N
|
||||
.collect(Collectors.toList());
|
||||
|
||||
/*
|
||||
* JFX components
|
||||
*/
|
||||
private final ProgressBar progressBar = new ProgressBar();
|
||||
private final MaskerPane maskerPane = new MaskerPane();
|
||||
private Group masterGroup;
|
||||
private ImageTagsGroup tagsGroup;
|
||||
private ImageTagCreator imageTagCreator;
|
||||
private ImageView fxImageView;
|
||||
private ScrollPane scrollPane;
|
||||
private final ProgressBar progressBar = new ProgressBar();
|
||||
private final MaskerPane maskerPane = new MaskerPane();
|
||||
|
||||
private Task<Image> readImageTask;
|
||||
|
||||
/*
|
||||
* Swing components
|
||||
*/
|
||||
private final JPopupMenu imageTaggingOptions = new JPopupMenu();
|
||||
private final JMenuItem createTagMenuItem;
|
||||
private final JMenuItem deleteTagMenuItem;
|
||||
private final JMenuItem hideTagsMenuItem;
|
||||
private final JMenuItem exportTagsMenuItem;
|
||||
|
||||
private final JFileChooser exportChooser;
|
||||
|
||||
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
|
||||
|
||||
private JFXPanel fxPanel;
|
||||
|
||||
/*
|
||||
* State
|
||||
*/
|
||||
private final boolean fxInited;
|
||||
private double zoomRatio;
|
||||
private double rotation; // Can be 0, 90, 180, and 270.
|
||||
|
||||
private boolean autoResize = true; // Auto resize when the user changes the size
|
||||
// of the content viewer unless the user has used the zoom buttons.
|
||||
private static final double[] ZOOM_STEPS = {
|
||||
0.0625, 0.125, 0.25, 0.375, 0.5, 0.75,
|
||||
1, 1.5, 2, 2.5, 3, 4, 5, 6, 8, 10};
|
||||
|
||||
private static final double MIN_ZOOM_RATIO = 0.0625; // 6.25%
|
||||
private static final double MAX_ZOOM_RATIO = 10.0; // 1000%
|
||||
private boolean autoResize = true; // Auto resize when the user changes the size of the content viewer unless the user has used the zoom buttons.
|
||||
private AbstractFile file;
|
||||
|
||||
static {
|
||||
ImageIO.scanForPlugins();
|
||||
}
|
||||
|
||||
/**
|
||||
* mime types we should be able to display. if the mimetype is unknown we
|
||||
* will fall back on extension and jpg/png header
|
||||
*/
|
||||
static private final SortedSet<String> supportedMimes = ImageUtils.getSupportedImageMimeTypes();
|
||||
|
||||
/**
|
||||
* extensions we should be able to display
|
||||
*/
|
||||
static private final List<String> supportedExtensions = ImageUtils.getSupportedImageExtensions().stream()
|
||||
.map("."::concat) //NOI18N
|
||||
.collect(Collectors.toList());
|
||||
|
||||
private Task<Image> readImageTask;
|
||||
|
||||
/**
|
||||
* Creates new form MediaViewImagePanel
|
||||
*/
|
||||
@@ -168,7 +164,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
"MediaViewImagePanel.hideTagOption=Hide",
|
||||
"MediaViewImagePanel.exportTagOption=Export"
|
||||
})
|
||||
public MediaViewImagePanel() {
|
||||
MediaViewImagePanel() {
|
||||
initComponents();
|
||||
fxInited = org.sleuthkit.autopsy.core.Installer.isJavaFxInited();
|
||||
|
||||
@@ -354,14 +350,13 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
}
|
||||
|
||||
private void showErrorNode(String errorMessage, AbstractFile file) {
|
||||
final Button externalViewerButton = new Button(Bundle.MediaViewImagePanel_externalViewerButton_text(), new ImageView(EXTERNAL));
|
||||
externalViewerButton.setOnAction(actionEvent
|
||||
-> //fx ActionEvent
|
||||
/*
|
||||
* TODO: why is the name passed into the action constructor? it
|
||||
* means we duplicate this string all over the place -jm
|
||||
*/ new ExternalViewerAction(Bundle.MediaViewImagePanel_externalViewerButton_text(), new FileNode(file))
|
||||
.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "")) //Swing ActionEvent
|
||||
final Button externalViewerButton = new Button(Bundle.MediaViewImagePanel_externalViewerButton_text(), new ImageView(externalImage));
|
||||
/*
|
||||
* Tie a Swing action (ExternalViewerAction) to a JFX button action.
|
||||
*/
|
||||
externalViewerButton.setOnAction(actionEvent ->
|
||||
new ExternalViewerAction(Bundle.MediaViewImagePanel_externalViewerButton_text(), new FileNode(file))
|
||||
.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, ""))
|
||||
);
|
||||
|
||||
final VBox errorNode = new VBox(10, new Label(errorMessage), externalViewerButton);
|
||||
@@ -420,7 +415,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
"state", null, State.NONEMPTY));
|
||||
}
|
||||
} catch (TskCoreException | NoCurrentCaseException ex) {
|
||||
LOGGER.log(Level.WARNING, "Could not retrieve image tags for file in case db", ex); //NON-NLS
|
||||
logger.log(Level.WARNING, "Could not retrieve image tags for file in case db", ex); //NON-NLS
|
||||
}
|
||||
scrollPane.setContent(masterGroup);
|
||||
} else {
|
||||
@@ -693,14 +688,14 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
|
||||
private void rotateLeftButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rotateLeftButtonActionPerformed
|
||||
autoResize = false;
|
||||
|
||||
|
||||
rotation = (rotation + 270) % 360;
|
||||
updateView();
|
||||
}//GEN-LAST:event_rotateLeftButtonActionPerformed
|
||||
|
||||
private void rotateRightButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rotateRightButtonActionPerformed
|
||||
autoResize = false;
|
||||
|
||||
|
||||
rotation = (rotation + 90) % 360;
|
||||
updateView();
|
||||
}//GEN-LAST:event_rotateRightButtonActionPerformed
|
||||
@@ -760,7 +755,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(contentViewerTag.getContentTag());
|
||||
tagsGroup.getChildren().remove(tagInFocus);
|
||||
} catch (TskCoreException | NoCurrentCaseException ex) {
|
||||
LOGGER.log(Level.WARNING, "Could not delete image tag in case db", ex); //NON-NLS
|
||||
logger.log(Level.WARNING, "Could not delete image tag in case db", ex); //NON-NLS
|
||||
}
|
||||
|
||||
scrollPane.setCursor(Cursor.DEFAULT);
|
||||
@@ -793,7 +788,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
ImageTag imageTag = buildImageTag(contentViewerTag);
|
||||
tagsGroup.getChildren().add(imageTag);
|
||||
} catch (TskCoreException | SerializationException | NoCurrentCaseException ex) {
|
||||
LOGGER.log(Level.WARNING, "Could not save new image tag in case db", ex); //NON-NLS
|
||||
logger.log(Level.WARNING, "Could not save new image tag in case db", ex); //NON-NLS
|
||||
}
|
||||
|
||||
scrollPane.setCursor(Cursor.DEFAULT);
|
||||
@@ -832,7 +827,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
ImageTagRegion newRegion = (ImageTagRegion) edit.getNewValue();
|
||||
ContentViewerTagManager.updateTag(contentViewerTag, newRegion);
|
||||
} catch (SerializationException | TskCoreException | NoCurrentCaseException ex) {
|
||||
LOGGER.log(Level.WARNING, "Could not save edit for image tag in case db", ex); //NON-NLS
|
||||
logger.log(Level.WARNING, "Could not save edit for image tag in case db", ex); //NON-NLS
|
||||
}
|
||||
scrollPane.setCursor(Cursor.DEFAULT);
|
||||
});
|
||||
@@ -916,7 +911,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
JOptionPane.showMessageDialog(null, Bundle.MediaViewImagePanel_successfulExport());
|
||||
} catch (Exception ex) { //Runtime exceptions may spill out of ImageTagsUtil from JavaFX.
|
||||
//This ensures we (devs and users) have something when it doesn't work.
|
||||
LOGGER.log(Level.WARNING, "Unable to export tagged image to disk", ex); //NON-NLS
|
||||
logger.log(Level.WARNING, "Unable to export tagged image to disk", ex); //NON-NLS
|
||||
JOptionPane.showMessageDialog(null, Bundle.MediaViewImagePanel_unsuccessfulExport());
|
||||
}
|
||||
return null;
|
||||
|
||||
+27
@@ -22,6 +22,8 @@ import java.nio.file.Path;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
||||
import org.sleuthkit.autopsy.ingest.IngestJobSettings;
|
||||
import org.sleuthkit.autopsy.ingest.IngestStream;
|
||||
|
||||
/**
|
||||
* Interface implemented by DataSourceProcessors in order to be supported by
|
||||
@@ -66,6 +68,31 @@ public interface AutoIngestDataSourceProcessor extends DataSourceProcessor {
|
||||
*/
|
||||
void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack);
|
||||
|
||||
|
||||
/**
|
||||
* Adds a data source to the case database using a background task in a
|
||||
* separate thread by calling DataSourceProcessor.run() method. Returns as
|
||||
* soon as the background task is started. The background task uses a
|
||||
* callback object to signal task completion and return results. Method can
|
||||
* throw an exception for a system level problem. The exception should not
|
||||
* be thrown for an issue related to bad input data.
|
||||
*
|
||||
* @param deviceId An ASCII-printable identifier for the device
|
||||
* associated with the data source that is intended
|
||||
* to be unique across multiple cases (e.g., a UUID).
|
||||
* @param dataSourcePath Path to the data source.
|
||||
* @param settings The ingest job settings.
|
||||
* @param progressMonitor Progress monitor that will be used by the
|
||||
* background task to report progress.
|
||||
* @param callBack Callback that will be used by the background task
|
||||
* to return results.
|
||||
*
|
||||
* @return The new ingest stream or null if an error occurred. Errors will be handled by the callback.
|
||||
*/
|
||||
default IngestStream processWithIngestStream(String deviceId, Path dataSourcePath, IngestJobSettings settings, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack) {
|
||||
throw new UnsupportedOperationException("Streaming ingest not supported for this data source processor");
|
||||
}
|
||||
|
||||
/**
|
||||
* A custom exception for the use of AutomatedIngestDataSourceProcessor.
|
||||
*/
|
||||
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* 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.datamodel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
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.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.
|
||||
*/
|
||||
public class DataSourceAnalysisSummary {
|
||||
|
||||
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<>(Arrays.asList(
|
||||
"PHONE NUMBERS",
|
||||
"IP ADDRESSES",
|
||||
"EMAIL ADDRESSES",
|
||||
"URLS",
|
||||
"CREDIT CARD NUMBERS"
|
||||
));
|
||||
|
||||
private final SleuthkitCaseProvider provider;
|
||||
|
||||
/**
|
||||
* Main constructor.
|
||||
*/
|
||||
public DataSourceAnalysisSummary() {
|
||||
this(SleuthkitCaseProvider.DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main constructor.
|
||||
*
|
||||
* @param provider The means of obtaining a sleuthkit case.
|
||||
*/
|
||||
public DataSourceAnalysisSummary(SleuthkitCaseProvider provider) {
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 getCountsData(dataSource, TYPE_SET_NAME, ARTIFACT_TYPE.TSK_HASHSET_HIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 getCountsData(dataSource, TYPE_SET_NAME, ARTIFACT_TYPE.TSK_KEYWORD_HIT).stream()
|
||||
// make sure we have a valid set and that that set does not belong to the set of excluded items
|
||||
.filter((pair) -> pair != null && pair.getKey() != null && !EXCLUDED_KEYWORD_SEARCH_ITEMS.contains(pair.getKey().toUpperCase().trim()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 getCountsData(dataSource, TYPE_SET_NAME, ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get counts for the artifact of the specified type.
|
||||
*
|
||||
* @param dataSource The datasource.
|
||||
* @param keyType The attribute to use as the key type.
|
||||
* @param artifactTypes The types of artifacts for which to query.
|
||||
*
|
||||
* @return A list of key value pairs where the key is the attribute type
|
||||
* value and the value is the count of items found. This list is
|
||||
* sorted by the count descending max to min.
|
||||
*
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
private List<Pair<String, Long>> getCountsData(DataSource dataSource, BlackboardAttribute.Type keyType, ARTIFACT_TYPE... artifactTypes)
|
||||
throws SleuthkitCaseProviderException, TskCoreException {
|
||||
List<BlackboardArtifact> artifacts = new ArrayList<>();
|
||||
SleuthkitCase skCase = provider.get();
|
||||
|
||||
// get all artifacts in one list for each artifact type
|
||||
for (ARTIFACT_TYPE type : artifactTypes) {
|
||||
artifacts.addAll(skCase.getBlackboard().getArtifacts(type.getTypeID(), dataSource.getId()));
|
||||
}
|
||||
|
||||
// group those based on the value of the attribute type that should serve as a key
|
||||
Map<String, Long> countedKeys = artifacts.stream()
|
||||
.map((art) -> {
|
||||
String key = DataSourceInfoUtilities.getStringOrNull(art, keyType);
|
||||
return (StringUtils.isBlank(key)) ? null : key;
|
||||
})
|
||||
.filter((key) -> key != null)
|
||||
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
|
||||
|
||||
// sort from max to min counts
|
||||
return countedKeys.entrySet().stream()
|
||||
.map((e) -> Pair.of(e.getKey(), e.getValue()))
|
||||
.sorted((a, b) -> -a.getValue().compareTo(b.getValue()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.4" 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">
|
||||
<Component id="mainScrollPane" alignment="0" pref="756" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="mainScrollPane" alignment="0" pref="300" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JScrollPane" name="mainScrollPane">
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JPanel" name="mainContentPanel">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.EmptyBorderInfo">
|
||||
<EmptyBorder bottom="10" left="10" right="10" top="10"/>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[32767, 452]"/>
|
||||
</Property>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[200, 452]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout">
|
||||
<Property name="axis" type="int" value="3"/>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="hashsetHitsLabel">
|
||||
<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="AnalysisPanel.hashsetHitsLabel.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.Box$Filler" name="filler1">
|
||||
<Properties>
|
||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[32767, 2]"/>
|
||||
</Property>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[0, 2]"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[0, 2]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.VerticalStrut"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Container class="javax.swing.JPanel" name="hashSetHitsPanel">
|
||||
<Properties>
|
||||
<Property name="alignmentX" type="float" value="0.0"/>
|
||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[32767, 106]"/>
|
||||
</Property>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[10, 106]"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[10, 106]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="hashsetHitsTable"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
|
||||
</Container>
|
||||
<Component class="javax.swing.Box$Filler" name="filler2">
|
||||
<Properties>
|
||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[32767, 20]"/>
|
||||
</Property>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[0, 20]"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[0, 20]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.VerticalStrut"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="keywordHitsLabel">
|
||||
<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="AnalysisPanel.keywordHitsLabel.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.Box$Filler" name="filler4">
|
||||
<Properties>
|
||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[32767, 2]"/>
|
||||
</Property>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[0, 2]"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[0, 2]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.VerticalStrut"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Container class="javax.swing.JPanel" name="keywordHitsPanel">
|
||||
<Properties>
|
||||
<Property name="alignmentX" type="float" value="0.0"/>
|
||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[32767, 106]"/>
|
||||
</Property>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[10, 106]"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[10, 106]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="keywordHitsTable"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
|
||||
</Container>
|
||||
<Component class="javax.swing.Box$Filler" name="filler5">
|
||||
<Properties>
|
||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[32767, 20]"/>
|
||||
</Property>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[0, 20]"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[0, 20]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.VerticalStrut"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="interestingItemLabel">
|
||||
<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="AnalysisPanel.interestingItemLabel.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.Box$Filler" name="filler6">
|
||||
<Properties>
|
||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[32767, 2]"/>
|
||||
</Property>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[0, 2]"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[0, 2]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.VerticalStrut"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Container class="javax.swing.JPanel" name="interestingItemPanel">
|
||||
<Properties>
|
||||
<Property name="alignmentX" type="float" value="0.0"/>
|
||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[32767, 106]"/>
|
||||
</Property>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[10, 106]"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[10, 106]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="interestingItemsTable"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
|
||||
</Container>
|
||||
<Component class="javax.swing.Box$Filler" name="filler3">
|
||||
<Properties>
|
||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[0, 32767]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.VerticalGlue"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* 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.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataSourceAnalysisSummary;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.DefaultCellModel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel.ColumnModel;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
|
||||
/**
|
||||
* A tab shown in data source summary displaying hash set hits, keyword hits,
|
||||
* and interesting item hits within a datasource.
|
||||
*/
|
||||
@Messages({
|
||||
"AnalysisPanel_keyColumn_title=Name",
|
||||
"AnalysisPanel_countColumn_title=Count"
|
||||
})
|
||||
public class AnalysisPanel extends BaseDataSourceSummaryPanel {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Default Column definitions for each table
|
||||
*/
|
||||
private static final List<ColumnModel<Pair<String, Long>>> DEFAULT_COLUMNS = Arrays.asList(
|
||||
new ColumnModel<>(
|
||||
Bundle.AnalysisPanel_keyColumn_title(),
|
||||
(pair) -> new DefaultCellModel(pair.getKey()),
|
||||
300
|
||||
),
|
||||
new ColumnModel<>(
|
||||
Bundle.AnalysisPanel_countColumn_title(),
|
||||
(pair) -> new DefaultCellModel(String.valueOf(pair.getValue())),
|
||||
100
|
||||
)
|
||||
);
|
||||
|
||||
private final JTablePanel<Pair<String, Long>> hashsetHitsTable = JTablePanel.getJTablePanel(DEFAULT_COLUMNS);
|
||||
|
||||
private final JTablePanel<Pair<String, Long>> keywordHitsTable = JTablePanel.getJTablePanel(DEFAULT_COLUMNS);
|
||||
|
||||
private final JTablePanel<Pair<String, Long>> interestingItemsTable = JTablePanel.getJTablePanel(DEFAULT_COLUMNS);
|
||||
|
||||
private final List<JTablePanel<?>> tables = Arrays.asList(
|
||||
hashsetHitsTable,
|
||||
keywordHitsTable,
|
||||
interestingItemsTable
|
||||
);
|
||||
|
||||
/**
|
||||
* All of the components necessary for data fetch swing workers to load data
|
||||
* for each table.
|
||||
*/
|
||||
private final List<DataFetchWorker.DataFetchComponents<DataSource, ?>> dataFetchComponents;
|
||||
|
||||
/**
|
||||
* Creates a new DataSourceUserActivityPanel.
|
||||
*/
|
||||
public AnalysisPanel() {
|
||||
this(new DataSourceAnalysisSummary());
|
||||
}
|
||||
|
||||
public AnalysisPanel(DataSourceAnalysisSummary analysisData) {
|
||||
// set up data acquisition methods
|
||||
dataFetchComponents = Arrays.asList(
|
||||
// hashset hits loading components
|
||||
new DataFetchWorker.DataFetchComponents<>(
|
||||
(dataSource) -> analysisData.getHashsetCounts(dataSource),
|
||||
(result) -> hashsetHitsTable.showDataFetchResult(result)),
|
||||
// keyword hits loading components
|
||||
new DataFetchWorker.DataFetchComponents<>(
|
||||
(dataSource) -> analysisData.getKeywordCounts(dataSource),
|
||||
(result) -> keywordHitsTable.showDataFetchResult(result)),
|
||||
// interesting item hits loading components
|
||||
new DataFetchWorker.DataFetchComponents<>(
|
||||
(dataSource) -> analysisData.getInterestingItemCounts(dataSource),
|
||||
(result) -> interestingItemsTable.showDataFetchResult(result))
|
||||
);
|
||||
|
||||
initComponents();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewDataSource(DataSource dataSource) {
|
||||
// if no data source is present or the case is not open,
|
||||
// set results for tables to null.
|
||||
if (dataSource == null || !Case.isCaseOpen()) {
|
||||
this.dataFetchComponents.forEach((item) -> item.getResultHandler()
|
||||
.accept(DataFetchResult.getSuccessResult(null)));
|
||||
|
||||
} else {
|
||||
// set tables to display loading screen
|
||||
this.tables.forEach((table) -> table.showDefaultLoadingMessage());
|
||||
|
||||
// create swing workers to run for each table
|
||||
List<DataFetchWorker<?, ?>> workers = dataFetchComponents
|
||||
.stream()
|
||||
.map((components) -> new DataFetchWorker<>(components, dataSource))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// submit swing workers to run
|
||||
submit(workers);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.JScrollPane mainScrollPane = new javax.swing.JScrollPane();
|
||||
javax.swing.JPanel mainContentPanel = new javax.swing.JPanel();
|
||||
javax.swing.JLabel hashsetHitsLabel = new javax.swing.JLabel();
|
||||
javax.swing.Box.Filler filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(32767, 2));
|
||||
javax.swing.JPanel hashSetHitsPanel = hashsetHitsTable;
|
||||
javax.swing.Box.Filler filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20), new java.awt.Dimension(32767, 20));
|
||||
javax.swing.JLabel keywordHitsLabel = new javax.swing.JLabel();
|
||||
javax.swing.Box.Filler filler4 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(32767, 2));
|
||||
javax.swing.JPanel keywordHitsPanel = keywordHitsTable;
|
||||
javax.swing.Box.Filler filler5 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20), new java.awt.Dimension(32767, 20));
|
||||
javax.swing.JLabel interestingItemLabel = new javax.swing.JLabel();
|
||||
javax.swing.Box.Filler filler6 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(32767, 2));
|
||||
javax.swing.JPanel interestingItemPanel = interestingItemsTable;
|
||||
javax.swing.Box.Filler filler3 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 32767));
|
||||
|
||||
mainContentPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
||||
mainContentPanel.setMaximumSize(new java.awt.Dimension(32767, 452));
|
||||
mainContentPanel.setMinimumSize(new java.awt.Dimension(200, 452));
|
||||
mainContentPanel.setLayout(new javax.swing.BoxLayout(mainContentPanel, javax.swing.BoxLayout.PAGE_AXIS));
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(hashsetHitsLabel, org.openide.util.NbBundle.getMessage(AnalysisPanel.class, "AnalysisPanel.hashsetHitsLabel.text")); // NOI18N
|
||||
mainContentPanel.add(hashsetHitsLabel);
|
||||
mainContentPanel.add(filler1);
|
||||
|
||||
hashSetHitsPanel.setAlignmentX(0.0F);
|
||||
hashSetHitsPanel.setMaximumSize(new java.awt.Dimension(32767, 106));
|
||||
hashSetHitsPanel.setMinimumSize(new java.awt.Dimension(10, 106));
|
||||
hashSetHitsPanel.setPreferredSize(new java.awt.Dimension(10, 106));
|
||||
mainContentPanel.add(hashSetHitsPanel);
|
||||
mainContentPanel.add(filler2);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(keywordHitsLabel, org.openide.util.NbBundle.getMessage(AnalysisPanel.class, "AnalysisPanel.keywordHitsLabel.text")); // NOI18N
|
||||
mainContentPanel.add(keywordHitsLabel);
|
||||
mainContentPanel.add(filler4);
|
||||
|
||||
keywordHitsPanel.setAlignmentX(0.0F);
|
||||
keywordHitsPanel.setMaximumSize(new java.awt.Dimension(32767, 106));
|
||||
keywordHitsPanel.setMinimumSize(new java.awt.Dimension(10, 106));
|
||||
keywordHitsPanel.setPreferredSize(new java.awt.Dimension(10, 106));
|
||||
mainContentPanel.add(keywordHitsPanel);
|
||||
mainContentPanel.add(filler5);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(interestingItemLabel, org.openide.util.NbBundle.getMessage(AnalysisPanel.class, "AnalysisPanel.interestingItemLabel.text")); // NOI18N
|
||||
mainContentPanel.add(interestingItemLabel);
|
||||
mainContentPanel.add(filler6);
|
||||
|
||||
interestingItemPanel.setAlignmentX(0.0F);
|
||||
interestingItemPanel.setMaximumSize(new java.awt.Dimension(32767, 106));
|
||||
interestingItemPanel.setMinimumSize(new java.awt.Dimension(10, 106));
|
||||
interestingItemPanel.setPreferredSize(new java.awt.Dimension(10, 106));
|
||||
mainContentPanel.add(interestingItemPanel);
|
||||
mainContentPanel.add(filler3);
|
||||
|
||||
mainScrollPane.setViewportView(mainContentPanel);
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(mainScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 756, Short.MAX_VALUE)
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(mainScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
||||
+10
-13
@@ -47,11 +47,6 @@ import org.sleuthkit.datamodel.DataSource;
|
||||
abstract class BaseDataSourceSummaryPanel extends JPanel {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final Set<String> INGEST_MODULE_EVENTS = new HashSet<String>(Arrays.asList(
|
||||
IngestManager.IngestModuleEvent.DATA_ADDED.toString(),
|
||||
IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString()
|
||||
));
|
||||
|
||||
private final SwingWorkerSequentialExecutor executor = new SwingWorkerSequentialExecutor();
|
||||
|
||||
@@ -81,14 +76,7 @@ abstract class BaseDataSourceSummaryPanel extends JPanel {
|
||||
}
|
||||
});
|
||||
|
||||
protected boolean isRefreshRequired(ModuleDataEvent evt) {
|
||||
return isRefreshRequiredForArtifactTypeId(evt.getBlackboardArtifactType().getTypeID());
|
||||
}
|
||||
|
||||
protected abstract boolean isRefreshRequiredForArtifactTypeId(int id);
|
||||
|
||||
|
||||
protected abstract boolean isRefreshRequired(ModuleContentEvent evt);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -98,6 +86,15 @@ abstract class BaseDataSourceSummaryPanel extends JPanel {
|
||||
protected BaseDataSourceSummaryPanel() {
|
||||
refreshThrottler.registerForIngestModuleEvents();
|
||||
}
|
||||
|
||||
protected boolean isRefreshRequired(ModuleDataEvent evt) {
|
||||
return isRefreshRequiredForArtifactTypeId(evt.getBlackboardArtifactType().getTypeID());
|
||||
}
|
||||
|
||||
protected abstract boolean isRefreshRequiredForArtifactTypeId(int id);
|
||||
|
||||
|
||||
protected abstract boolean isRefreshRequired(ModuleContentEvent evt);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -33,6 +33,9 @@ DataSourceSummaryUserActivityPanel.recentAccountsLabel.text=Recent Accounts
|
||||
DataSourceSummaryUserActivityPanel.topWebSearchLabel.text=Recent Web Searches
|
||||
DataSourceSummaryUserActivityPanel.topDevicesAttachedLabel.text=Recent Devices Attached
|
||||
DataSourceSummaryUserActivityPanel.recentDomainsLabel.text=Recent Domains
|
||||
AnalysisPanel.hashsetHitsLabel.text=Hashset Hits
|
||||
AnalysisPanel.keywordHitsLabel.text=Keyword Hits
|
||||
AnalysisPanel.interestingItemLabel.text=Interesting Item Hits
|
||||
RecentFilesPanel.openDocsLabel.text=Recently Opened Documents
|
||||
RecentFilesPanel.downloadLabel.text=Recent Downloads
|
||||
RecentFilesPanel.attachmentLabel.text=Recent Attachements
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
AnalysisPanel_countColumn_title=Count
|
||||
AnalysisPanel_keyColumn_title=Name
|
||||
CTL_DataSourceSummaryAction=Data Source Summary
|
||||
DataSourceSummaryDetailsPanel.getDataSources.error.text=Failed to get the list of datasources for the current case.
|
||||
DataSourceSummaryDetailsPanel.getDataSources.error.title=Load Failure
|
||||
@@ -39,6 +41,7 @@ DataSourceSummaryNode.column.status.header=Ingest Status
|
||||
DataSourceSummaryNode.column.tags.header=Tags
|
||||
DataSourceSummaryNode.column.type.header=Type
|
||||
DataSourceSummaryNode.viewDataSourceAction.text=Go to Data Source
|
||||
DataSourceSummaryTabbedPane_analysisTab_title=Analysis
|
||||
DataSourceSummaryTabbedPane_detailsTab_title=Container
|
||||
DataSourceSummaryTabbedPane_ingestHistoryTab_title=Ingest History
|
||||
DataSourceSummaryTabbedPane_recentFileTab_title=Recent Files
|
||||
@@ -49,6 +52,9 @@ DataSourceSummaryUserActivityPanel.recentAccountsLabel.text=Recent Accounts
|
||||
DataSourceSummaryUserActivityPanel.topWebSearchLabel.text=Recent Web Searches
|
||||
DataSourceSummaryUserActivityPanel.topDevicesAttachedLabel.text=Recent Devices Attached
|
||||
DataSourceSummaryUserActivityPanel.recentDomainsLabel.text=Recent Domains
|
||||
AnalysisPanel.hashsetHitsLabel.text=Hashset Hits
|
||||
AnalysisPanel.keywordHitsLabel.text=Keyword Hits
|
||||
AnalysisPanel.interestingItemLabel.text=Interesting Item Hits
|
||||
DataSourceSummaryUserActivityPanel_noDataExists=No communication data exists
|
||||
DataSourceSummaryUserActivityPanel_tab_title=User Activity
|
||||
DataSourceSummaryUserActivityPanel_TopAccountTableModel_accountType_header=Account Type
|
||||
|
||||
+4
-2
@@ -37,7 +37,8 @@ import org.sleuthkit.datamodel.DataSource;
|
||||
"DataSourceSummaryTabbedPane_detailsTab_title=Container",
|
||||
"DataSourceSummaryTabbedPane_userActivityTab_title=User Activity",
|
||||
"DataSourceSummaryTabbedPane_ingestHistoryTab_title=Ingest History",
|
||||
"DataSourceSummaryTabbedPane_recentFileTab_title=Recent Files"
|
||||
"DataSourceSummaryTabbedPane_recentFileTab_title=Recent Files",
|
||||
"DataSourceSummaryTabbedPane_analysisTab_title=Analysis"
|
||||
})
|
||||
public class DataSourceSummaryTabbedPane extends JTabbedPane {
|
||||
|
||||
@@ -116,6 +117,7 @@ public class DataSourceSummaryTabbedPane extends JTabbedPane {
|
||||
new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_typesTab_title(), new TypesPanel()),
|
||||
new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_userActivityTab_title(), new DataSourceSummaryUserActivityPanel()),
|
||||
new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_recentFileTab_title(), new RecentFilesPanel()),
|
||||
new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_analysisTab_title(), new AnalysisPanel()),
|
||||
new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_ingestHistoryTab_title(), ingestHistoryPanel, ingestHistoryPanel::setDataSource, () -> {
|
||||
}),
|
||||
new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_detailsTab_title(), new DataSourceSummaryDetailsPanel())
|
||||
@@ -128,7 +130,7 @@ public class DataSourceSummaryTabbedPane extends JTabbedPane {
|
||||
*/
|
||||
public DataSourceSummaryTabbedPane() {
|
||||
initComponent();
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void initComponent() {
|
||||
|
||||
+2
-1
@@ -103,7 +103,8 @@ public class DataSourceSummaryUserActivityPanel extends BaseDataSourceSummaryPan
|
||||
return new DefaultCellModel(
|
||||
getShortFolderName(
|
||||
prog.getProgramPath(),
|
||||
prog.getProgramName()));
|
||||
prog.getProgramName()))
|
||||
.setTooltip(prog.getProgramPath());
|
||||
},
|
||||
150),
|
||||
// run count column
|
||||
|
||||
@@ -20,6 +20,8 @@ package org.sleuthkit.autopsy.discovery;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.swing.DefaultListCellRenderer;
|
||||
@@ -204,11 +206,30 @@ final class GroupListPanel extends javax.swing.JPanel {
|
||||
if (newValue instanceof GroupKey) {
|
||||
String valueString = newValue.toString();
|
||||
setToolTipText(valueString);
|
||||
//if paths would be longer than 37 characters shorten them to be 37 characters
|
||||
if (groupingAttribute instanceof FileSearch.ParentPathAttribute && valueString.length() > 37) {
|
||||
valueString = valueString.substring(0, 16) + " ... " + valueString.substring(valueString.length() - 16);
|
||||
|
||||
valueString += " (" + groupMap.get(newValue) + ")";
|
||||
|
||||
if (groupingAttribute instanceof FileSearch.ParentPathAttribute) {
|
||||
// Using the list FontRenderContext instead of this because
|
||||
// the label RenderContext was sometimes null, but this should work.
|
||||
FontRenderContext context = ((Graphics2D) list.getGraphics()).getFontRenderContext();
|
||||
|
||||
//Determine the width of the string with the given font.
|
||||
double stringWidth = getFont().getStringBounds(valueString, context).getWidth();
|
||||
// subtracting 10 from the width as a littl inset.
|
||||
int listWidth = list.getWidth() - 10;
|
||||
|
||||
if (stringWidth > listWidth) {
|
||||
double avgCharWidth = Math.floor(stringWidth / valueString.length());
|
||||
|
||||
// The extra 5 is to account for the " ... " that is being added back.
|
||||
int charToRemove = (int) Math.ceil((stringWidth - listWidth) / avgCharWidth) + 5;
|
||||
int charactersToShow = (int) Math.ceil((valueString.length() - charToRemove) / 2);
|
||||
valueString = valueString.substring(0, charactersToShow) + " ... " + valueString.substring(valueString.length() - charactersToShow);
|
||||
}
|
||||
|
||||
}
|
||||
newValue = valueString + " (" + groupMap.get(newValue) + ")";
|
||||
newValue = valueString;
|
||||
}
|
||||
super.getListCellRendererComponent(list, newValue, index, isSelected, cellHasFocus);
|
||||
return this;
|
||||
|
||||
@@ -58,6 +58,11 @@ class IngestJobInputStream implements IngestStream {
|
||||
}
|
||||
ingestJob.addStreamingIngestFiles(fileObjectIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IngestJob getIngestJob() {
|
||||
return ingestJob;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void close() {
|
||||
|
||||
@@ -34,6 +34,13 @@ public interface IngestStream {
|
||||
* @throws IngestStreamClosedException
|
||||
*/
|
||||
void addFiles(List<Long> fileObjectIds) throws IngestStreamClosedException;
|
||||
|
||||
/**
|
||||
* Get the ingest job associated with this ingest stream.
|
||||
*
|
||||
* @return The IngestJob.
|
||||
*/
|
||||
IngestJob getIngestJob();
|
||||
|
||||
/**
|
||||
* Closes the ingest stream. Should be called after all files from data
|
||||
|
||||
Reference in New Issue
Block a user