mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-12 07:56:16 +00:00
Merge branch 'artifacts_are_content' of https://github.com/sleuthkit/autopsy into 2689_artifacts_are_content
# Conflicts: # Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java
This commit is contained in:
commit
4fdea244af
@ -861,7 +861,7 @@ public class EamDbSettingsDialog extends JDialog {
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
@Messages({"EamDbSettingsDialog.validation.mustTest=Once you are statisfied with the database settings, click the Test button to test the database connection, settings, and schema.",
|
||||
@Messages({"EamDbSettingsDialog.validation.mustTest=Once you are statisfied with the database settings, click the Test button to test the database connection, settings, and schema. SQLite should only be used by one examiner at a time.",
|
||||
"EamDbSettingsDialog.validation.failedConnection=The connection to the database failed. Update the settings and try the Test again."})
|
||||
private boolean enableTestButton(boolean isValidInput) {
|
||||
if (selectedPlatform != EamDbPlatformEnum.DISABLED && isValidInput) {
|
||||
|
@ -220,6 +220,7 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer {
|
||||
|
||||
@Override
|
||||
public void resetComponent() {
|
||||
setText("");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -493,18 +493,19 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
|
||||
private final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
private String[][] rowData = null;
|
||||
private final String artifactDisplayName;
|
||||
private final Content content;
|
||||
|
||||
ResultsTableArtifact(BlackboardArtifact artifact) {
|
||||
ResultsTableArtifact(BlackboardArtifact artifact, Content content) {
|
||||
artifactDisplayName = artifact.getDisplayName();
|
||||
this.content = content;
|
||||
addRows(artifact);
|
||||
|
||||
}
|
||||
|
||||
ResultsTableArtifact(String errorMsg) {
|
||||
artifactDisplayName = errorMsg;
|
||||
rowData = new String[1][3];
|
||||
rowData[0] = new String[]{"", errorMsg, ""};
|
||||
|
||||
content = null;
|
||||
}
|
||||
|
||||
private String[][] getRows() {
|
||||
@ -514,7 +515,6 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
|
||||
private void addRows(BlackboardArtifact artifact) {
|
||||
List<String[]> rowsToAdd = new ArrayList<>();
|
||||
try {
|
||||
Content content = artifact.getSleuthkitCase().getContentById(artifact.getObjectID());
|
||||
/*
|
||||
* Add rows for each attribute.
|
||||
*/
|
||||
@ -701,12 +701,15 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
|
||||
if (contents.isEmpty()) {
|
||||
return new ViewUpdate(getArtifactContents().size(), currentPage, ERROR_TEXT);
|
||||
}
|
||||
Content underlyingContent = null;
|
||||
for (Content content : contents) {
|
||||
if ( (content != null) && (!(content instanceof BlackboardArtifact)) ) {
|
||||
// Get all of the blackboard artifacts associated with the content. These are what this
|
||||
// viewer displays.
|
||||
try {
|
||||
artifacts = content.getAllArtifacts();
|
||||
underlyingContent = content;
|
||||
break;
|
||||
} catch (TskException ex) {
|
||||
logger.log(Level.SEVERE, "Couldn't get artifacts", ex); //NON-NLS
|
||||
return new ViewUpdate(getArtifactContents().size(), currentPage, ERROR_TEXT);
|
||||
@ -721,7 +724,7 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
|
||||
// Build the new artifact contents cache.
|
||||
ArrayList<ResultsTableArtifact> artifactContents = new ArrayList<>();
|
||||
for (BlackboardArtifact artifact : artifacts) {
|
||||
artifactContents.add(new ResultsTableArtifact(artifact));
|
||||
artifactContents.add(new ResultsTableArtifact(artifact, underlyingContent));
|
||||
}
|
||||
|
||||
// If the node has an underlying blackboard artifact, show it. If not,
|
||||
|
@ -28,6 +28,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
@ -104,11 +105,11 @@ class ThumbnailViewChildren extends Children.Keys<Integer> {
|
||||
* children nodes (which might not be preloaded at this point).
|
||||
*/
|
||||
// get list of supported children sorted by persisted criteria
|
||||
final List<Node> suppContent =
|
||||
Stream.of(parent.getChildren().getNodes())
|
||||
.filter(ThumbnailViewChildren::isSupported)
|
||||
.sorted(getComparator())
|
||||
.collect(Collectors.toList());
|
||||
final List<Node> suppContent
|
||||
= Stream.of(parent.getChildren().getNodes())
|
||||
.filter(ThumbnailViewChildren::isSupported)
|
||||
.sorted(getComparator())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (suppContent.isEmpty()) {
|
||||
//if there are no images, there is nothing more to do
|
||||
@ -314,7 +315,12 @@ class ThumbnailViewChildren extends Children.Keys<Integer> {
|
||||
private boolean cancelled = false;
|
||||
|
||||
ThumbnailLoadTask() {
|
||||
super(() -> ImageUtils.getThumbnail(content, thumbSize));
|
||||
super(new Callable<Image>() { //Does not work as lambda expression in dependent projects in IDE
|
||||
public Image call() {
|
||||
return ImageUtils.getThumbnail(content, thumbSize);
|
||||
}
|
||||
});
|
||||
//super(() -> ImageUtils.getThumbnail(content, thumbSize));
|
||||
progressText = Bundle.ThumbnailViewNode_progressHandle_text(content.getName());
|
||||
|
||||
progressHandle = ProgressHandleFactory.createSystemHandle(progressText);
|
||||
|
@ -18,6 +18,8 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.text.MessageFormat;
|
||||
@ -26,6 +28,8 @@ import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.swing.Action;
|
||||
@ -35,12 +39,12 @@ import org.openide.util.Lookup;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagAddedEvent;
|
||||
import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagDeletedEvent;
|
||||
import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent;
|
||||
import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import static org.sleuthkit.autopsy.datamodel.DisplayableItemNode.findLinked;
|
||||
import org.sleuthkit.autopsy.timeline.actions.ViewArtifactInTimelineAction;
|
||||
import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction;
|
||||
@ -59,10 +63,15 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
*/
|
||||
public class BlackboardArtifactNode extends DisplayableItemNode {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(BlackboardArtifactNode.class.getName());
|
||||
|
||||
private static Cache<Long, Content> contentCache = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(1, TimeUnit.MINUTES).
|
||||
build();
|
||||
|
||||
private final BlackboardArtifact artifact;
|
||||
private Content associated = null;
|
||||
private List<NodeProperty<? extends Object>> customProperties;
|
||||
private static final Logger LOGGER = Logger.getLogger(BlackboardArtifactNode.class.getName());
|
||||
/*
|
||||
* Artifact types which should have the full unique path of the associated
|
||||
* content as a property.
|
||||
@ -107,6 +116,7 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
|
||||
if (evt.getNewValue() == null) {
|
||||
// case was closed. Remove listeners so that we don't get called with a stale case handle
|
||||
removeListeners();
|
||||
contentCache.invalidateAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -297,7 +307,7 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
|
||||
// Do nothing since the display name will be set to the file name.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
||||
ss.put(new NodeProperty<>(entry.getKey(),
|
||||
entry.getKey(),
|
||||
@ -491,46 +501,46 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
|
||||
LOGGER.log(Level.SEVERE, "Getting attributes failed", ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fill map with EmailMsg properties, not all attributes are filled
|
||||
*
|
||||
* @param map map with preserved ordering, where property names/values
|
||||
* are put
|
||||
* @param attribute attribute to check/fill as property
|
||||
*/
|
||||
* Fill map with EmailMsg properties, not all attributes are filled
|
||||
*
|
||||
* @param map map with preserved ordering, where property names/values
|
||||
* are put
|
||||
* @param attribute attribute to check/fill as property
|
||||
*/
|
||||
private void addEmailMsgProperty(Map<String, Object> map, BlackboardAttribute attribute ) {
|
||||
|
||||
final int attributeTypeID = attribute.getAttributeType().getTypeID();
|
||||
|
||||
// Skip certain Email msg attributes
|
||||
if (attributeTypeID == ATTRIBUTE_TYPE.TSK_DATETIME_SENT.getTypeID()
|
||||
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML.getTypeID()
|
||||
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF.getTypeID()
|
||||
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_BCC.getTypeID()
|
||||
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CC.getTypeID()
|
||||
|
||||
final int attributeTypeID = attribute.getAttributeType().getTypeID();
|
||||
|
||||
// Skip certain Email msg attributes
|
||||
if (attributeTypeID == ATTRIBUTE_TYPE.TSK_DATETIME_SENT.getTypeID()
|
||||
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML.getTypeID()
|
||||
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF.getTypeID()
|
||||
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_BCC.getTypeID()
|
||||
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CC.getTypeID()
|
||||
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_HEADERS.getTypeID()
|
||||
) {
|
||||
|
||||
// do nothing
|
||||
|
||||
// do nothing
|
||||
}
|
||||
else if (attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_PLAIN.getTypeID()) {
|
||||
|
||||
String value = attribute.getDisplayString();
|
||||
if (value.length() > 160) {
|
||||
value = value.substring(0, 160) + "...";
|
||||
}
|
||||
map.put(attribute.getAttributeType().getDisplayName(), value);
|
||||
String value = attribute.getDisplayString();
|
||||
if (value.length() > 160) {
|
||||
value = value.substring(0, 160) + "...";
|
||||
}
|
||||
map.put(attribute.getAttributeType().getDisplayName(), value);
|
||||
}
|
||||
else if (attribute.getAttributeType().getValueType() == BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME) {
|
||||
map.put(attribute.getAttributeType().getDisplayName(), ContentUtils.getStringTime(attribute.getValueLong(), associated));
|
||||
map.put(attribute.getAttributeType().getDisplayName(), ContentUtils.getStringTime(attribute.getValueLong(), associated));
|
||||
}
|
||||
else {
|
||||
map.put(attribute.getAttributeType().getDisplayName(), attribute.getDisplayString());
|
||||
map.put(attribute.getAttributeType().getDisplayName(), attribute.getDisplayString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
@ -539,31 +549,25 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
|
||||
/**
|
||||
* Create a Lookup based on what is in the passed in artifact.
|
||||
*
|
||||
* @param artifact
|
||||
* @param artifact The artifact to make a look up for.
|
||||
*
|
||||
* @return
|
||||
* @return A lookup with the artifact and possibly any associated content in
|
||||
* it.
|
||||
*/
|
||||
private static Lookup createLookup(BlackboardArtifact artifact) {
|
||||
List<Object> forLookup = new ArrayList<>();
|
||||
forLookup.add(artifact);
|
||||
|
||||
// Add the content the artifact is associated with
|
||||
Content content = getAssociatedContent(artifact);
|
||||
if (content != null) {
|
||||
forLookup.add(content);
|
||||
}
|
||||
|
||||
return Lookups.fixed(forLookup.toArray(new Object[forLookup.size()]));
|
||||
}
|
||||
|
||||
private static Content getAssociatedContent(BlackboardArtifact artifact) {
|
||||
final long objectID = artifact.getObjectID();
|
||||
try {
|
||||
return artifact.getSleuthkitCase().getContentById(artifact.getObjectID());
|
||||
} catch (TskCoreException ex) {
|
||||
LOGGER.log(Level.WARNING, "Getting file failed", ex); //NON-NLS
|
||||
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.WARNING, "Getting associated content for artifact failed", ex); //NON-NLS
|
||||
return Lookups.fixed(artifact);
|
||||
}
|
||||
throw new IllegalArgumentException(
|
||||
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.getAssocCont.exception.msg"));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -42,7 +42,6 @@ BlackboardArtifactNode.createSheet.filePath.name=File Path
|
||||
BlackboardArtifactNode.createSheet.filePath.displayName=File Path
|
||||
BlackboardArtifactNode.createSheet.dataSrc.name=Data Source
|
||||
BlackboardArtifactNode.createSheet.dataSrc.displayName=Data Source
|
||||
BlackboardArtifactNode.getAssocCont.exception.msg=Could not get file from database
|
||||
BlackboardArtifactTagNode.createSheet.srcFile.text=Source File
|
||||
BlackboardArtifactTagNode.createSheet.unavail.text=Unavailable
|
||||
BlackboardArtifactTagNode.createSheet.srcFilePath.text=Source File Path
|
||||
@ -87,8 +86,8 @@ DeletedContent.deletedContentsNode.name=Deleted Files
|
||||
DeletedContent.createSheet.name.name=Name
|
||||
DeletedContent.createSheet.name.displayName=Name
|
||||
DeletedContent.createSheet.name.desc=no description
|
||||
DeletedContent.createSheet.filterType.name=Filter Type
|
||||
DeletedContent.createSheet.filterType.displayName=Filter Type
|
||||
DeletedContent.createSheet.filterType.name=Type
|
||||
DeletedContent.createSheet.filterType.displayName=Type
|
||||
DeletedContent.createSheet.filterType.desc=no description
|
||||
DeletedContent.createKeys.maxObjects.msg=There are more Deleted Files than can be displayed. Only the first {0} Deleted Files will be shown.
|
||||
DeletedContent.createNodeForKey.typeNotSupported.msg=Not supported for this type of Displayable Item\: {0}
|
||||
@ -112,13 +111,13 @@ FileSize.fileSizeRootNode.name=File Size
|
||||
FileSize.createSheet.name.name=Name
|
||||
FileSize.createSheet.name.displayName=Name
|
||||
FileSize.createSheet.name.desc=no description
|
||||
FileSize.createSheet.filterType.name=Filter Type
|
||||
FileSize.createSheet.filterType.displayName=Filter Type
|
||||
FileSize.createSheet.filterType.name=Size Range
|
||||
FileSize.createSheet.filterType.displayName=Size Range
|
||||
FileSize.createSheet.filterType.desc=no description
|
||||
FileSize.exception.notSupported.msg=Not supported for this type of Displayable Item\: {0}
|
||||
FileTypeChildren.exception.notSupported.msg=Not supported for this type of Displayable Item\: {0}
|
||||
FileTypesByExtNode.createSheet.filterType.name=Filter Type
|
||||
FileTypesByExtNode.createSheet.filterType.displayName=Filter Type
|
||||
FileTypesByExtNode.createSheet.filterType.name=File Type
|
||||
FileTypesByExtNode.createSheet.filterType.displayName=File Type
|
||||
FileTypesByExtNode.createSheet.filterType.desc=no description
|
||||
FileTypesByExtNode.createSheet.fileExt.name=File Extensions
|
||||
FileTypesByExtNode.createSheet.fileExt.displayName=File Extensions
|
||||
|
@ -32,7 +32,6 @@ BlackboardArtifactNode.createSheet.filePath.name=\u30d5\u30a1\u30a4\u30eb\u30d1\
|
||||
BlackboardArtifactNode.createSheet.filePath.displayName=\u30d5\u30a1\u30a4\u30eb\u30d1\u30b9
|
||||
BlackboardArtifactNode.createSheet.dataSrc.name=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9
|
||||
BlackboardArtifactNode.createSheet.dataSrc.displayName=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9
|
||||
BlackboardArtifactNode.getAssocCont.exception.msg=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304b\u3089\u30d5\u30a1\u30a4\u30eb\u3092\u53d6\u5f97\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
|
||||
BlackboardArtifactTagNode.createSheet.srcFile.text=\u30bd\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb
|
||||
BlackboardArtifactTagNode.createSheet.unavail.text=\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093
|
||||
BlackboardArtifactTagNode.createSheet.srcFilePath.text=\u30bd\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb\u30d1\u30b9
|
||||
@ -64,8 +63,6 @@ DataSourcesNode.createSheet.name.desc=\u8aac\u660e\u304c\u3042\u308a\u307e\u305b
|
||||
DeletedContent.fsDelFilter.text=\u30d5\u30a1\u30a4\u30eb\u30b7\u30b9\u30c6\u30e0
|
||||
DeletedContent.allDelFilter.text=\u3059\u3079\u3066
|
||||
DeletedContent.deletedContentsNode.name=\u524a\u9664\u3055\u308c\u305f\u30d5\u30a1\u30a4\u30eb
|
||||
DeletedContent.createSheet.name.name=\u540d\u524d
|
||||
DeletedContent.createSheet.name.displayName=\u540d\u524d
|
||||
DeletedContent.createSheet.name.desc=\u8aac\u660e\u304c\u3042\u308a\u307e\u305b\u3093
|
||||
DeletedContent.createSheet.filterType.name=\u30d5\u30a3\u30eb\u30bf\u30fc\u30bf\u30a4\u30d7
|
||||
DeletedContent.createSheet.filterType.displayName=\u30d5\u30a3\u30eb\u30bf\u30fc\u30bf\u30a4\u30d7
|
||||
@ -92,8 +89,6 @@ FileNode.getActions.viewInNewWin.text=\u65b0\u898f\u30a6\u30a3\u30f3\u30c9\u30a6
|
||||
FileNode.getActions.openInExtViewer.text=\u5916\u90e8\u30d3\u30e5\u30fc\u30a2\u3067\u958b\u304f
|
||||
FileNode.getActions.searchFilesSameMD5.text=\u540c\u3058MD5\u30cf\u30c3\u30b7\u30e5\u3092\u6301\u3064\u30d5\u30a1\u30a4\u30eb\u3092\u691c\u7d22
|
||||
FileSize.fileSizeRootNode.name=\u30d5\u30a1\u30a4\u30eb\u30b5\u30a4\u30ba
|
||||
FileSize.createSheet.name.name=\u540d\u524d
|
||||
FileSize.createSheet.name.displayName=\u540d\u524d
|
||||
FileSize.createSheet.name.desc=\u8aac\u660e\u304c\u3042\u308a\u307e\u305b\u3093
|
||||
FileSize.createSheet.filterType.name=\u30d5\u30a3\u30eb\u30bf\u30fc\u30bf\u30a4\u30d7
|
||||
FileSize.createSheet.filterType.displayName=\u30d5\u30a3\u30eb\u30bf\u30fc\u30bf\u30a4\u30d7
|
||||
@ -111,8 +106,6 @@ FileTypeExtensionFilters.autDocOfficeFilter.text=\u30aa\u30d5\u30a3\u30b9
|
||||
FileTypeExtensionFilters.autoDocPdfFilter.text=PDF
|
||||
FileTypeExtensionFilters.autDocTxtFilter.text=\u30d7\u30ec\u30fc\u30f3\u30c6\u30ad\u30b9\u30c8
|
||||
FileTypeExtensionFilters.autDocRtfFilter.text=\u30ea\u30c3\u30c1\u30c6\u30ad\u30b9\u30c8
|
||||
FileTypesByExtNode.createSheet.filterType.name=\u30d5\u30a3\u30eb\u30bf\u30fc\u30bf\u30a4\u30d7
|
||||
FileTypesByExtNode.createSheet.filterType.displayName=\u30d5\u30a3\u30eb\u30bf\u30fc\u30bf\u30a4\u30d7
|
||||
FileTypesByExtNode.createSheet.filterType.desc=\u8aac\u660e\u304c\u3042\u308a\u307e\u305b\u3093
|
||||
FileTypesByExtNode.createSheet.fileExt.name=\u30d5\u30a1\u30a4\u30eb\u62e1\u5f35\u5b50
|
||||
FileTypesByExtNode.createSheet.fileExt.displayName=\u30d5\u30a1\u30a4\u30eb\u62e1\u5f35\u5b50
|
||||
|
@ -30,7 +30,6 @@ import org.openide.util.Utilities;
|
||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||
import org.sleuthkit.autopsy.coreutils.ImageUtils;
|
||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
||||
@ -62,8 +61,7 @@ public class FileNode extends AbstractFsContentNode<AbstractFile> {
|
||||
} else {
|
||||
ext = "." + ext;
|
||||
}
|
||||
if (ImageUtils.isImageThumbnailSupported(file)
|
||||
|| FileTypeExtensions.getImageExtensions().contains(ext)) {
|
||||
if (FileTypeExtensions.getImageExtensions().contains(ext)) {
|
||||
return "org/sleuthkit/autopsy/images/image-file.png"; //NON-NLS
|
||||
}
|
||||
if (FileTypeExtensions.getVideoExtensions().contains(ext)) {
|
||||
|
@ -45,6 +45,7 @@ import org.sleuthkit.datamodel.File;
|
||||
import org.sleuthkit.datamodel.FsContent;
|
||||
import org.sleuthkit.datamodel.LayoutFile;
|
||||
import org.sleuthkit.datamodel.LocalFile;
|
||||
import org.sleuthkit.datamodel.SlackFile;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
@ -483,6 +484,11 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
return new FileNode(f, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileNode visit(SlackFile f) {
|
||||
return new FileNode(f, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractNode defaultVisit(Content di) {
|
||||
throw new UnsupportedOperationException(
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Copyright 2011-2017 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -18,9 +18,12 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.SwingWorker;
|
||||
@ -31,6 +34,8 @@ import org.openide.util.Lookup;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.ContentVisitor;
|
||||
import org.sleuthkit.datamodel.DerivedFile;
|
||||
@ -40,6 +45,7 @@ import org.sleuthkit.datamodel.LayoutFile;
|
||||
import org.sleuthkit.datamodel.LocalFile;
|
||||
import org.sleuthkit.datamodel.SlackFile;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.SleuthkitItemVisitor;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
@ -47,10 +53,24 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
*/
|
||||
public final class FileTypes implements AutopsyVisitableItem {
|
||||
|
||||
private final static Logger logger = Logger.getLogger(FileTypes.class.getName());
|
||||
private static final Logger logger = Logger.getLogger(FileTypes.class.getName());
|
||||
@NbBundle.Messages("FileTypes.name.text=File Types")
|
||||
private static final String NAME = Bundle.FileTypes_name_text();
|
||||
/**
|
||||
* Threshold used to limit db queries for child node counts. When the
|
||||
* tsk_files table has more than this number of rows, we don't query for the
|
||||
* child node counts, and since we don't have an accurate number we don't
|
||||
* show the counts.
|
||||
*/
|
||||
private static final int NODE_COUNT_FILE_TABLE_THRESHOLD = 1_000_000;
|
||||
/**
|
||||
* Used to keep track of whether we have hit
|
||||
* NODE_COUNT_FILE_TABLE_THRESHOLD. If we have, we stop querying for the
|
||||
* number of rows in tsk_files, since it is already too large.
|
||||
*/
|
||||
private boolean showCounts = true;
|
||||
|
||||
private final SleuthkitCase skCase;
|
||||
private boolean showCounts = true;
|
||||
|
||||
FileTypes(SleuthkitCase skCase) {
|
||||
this.skCase = skCase;
|
||||
@ -66,15 +86,16 @@ public final class FileTypes implements AutopsyVisitableItem {
|
||||
}
|
||||
|
||||
/**
|
||||
* Should the nodes show counts?
|
||||
*
|
||||
*
|
||||
* @return True, unless the DB has more than 200k rows.
|
||||
* Check the db to determine if the nodes should show child counts.
|
||||
*/
|
||||
boolean shouldShowCounts() {
|
||||
void updateShowCounts() {
|
||||
/*
|
||||
* once we have passed the threshold, we don't need to keep checking the
|
||||
* number of rows in tsk_files
|
||||
*/
|
||||
if (showCounts) {
|
||||
try {
|
||||
if (skCase.countFilesWhere("1=1") > 200000) { //NON-NLS
|
||||
if (skCase.countFilesWhere("1=1") > NODE_COUNT_FILE_TABLE_THRESHOLD) { //NON-NLS
|
||||
showCounts = false;
|
||||
}
|
||||
} catch (TskCoreException tskCoreException) {
|
||||
@ -82,10 +103,7 @@ public final class FileTypes implements AutopsyVisitableItem {
|
||||
logger.log(Level.SEVERE, "Error counting files.", tskCoreException); //NON-NLS
|
||||
}
|
||||
}
|
||||
return showCounts;
|
||||
}
|
||||
@NbBundle.Messages("FileTypes.name.text=File Types")
|
||||
static private final String NAME = Bundle.FileTypes_name_text();
|
||||
|
||||
/**
|
||||
* Node which will contain By Mime Type and By Extension nodes.
|
||||
@ -97,8 +115,8 @@ public final class FileTypes implements AutopsyVisitableItem {
|
||||
new FileTypesByExtension(FileTypes.this),
|
||||
new FileTypesByMimeType(FileTypes.this))),
|
||||
Lookups.singleton(NAME));
|
||||
setName(NAME);
|
||||
setDisplayName(NAME);
|
||||
this.setName(NAME);
|
||||
this.setDisplayName(NAME);
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png"); //NON-NLS
|
||||
}
|
||||
|
||||
@ -215,9 +233,9 @@ public final class FileTypes implements AutopsyVisitableItem {
|
||||
* Updates the display name of the mediaSubTypeNode to include the count
|
||||
* of files which it represents.
|
||||
*/
|
||||
@NbBundle.Messages("FileTypes.bgCounting.placeholder=(counting...)")
|
||||
@NbBundle.Messages("FileTypes.bgCounting.placeholder= (counting...)")
|
||||
void updateDisplayName() {
|
||||
if (typesRoot.shouldShowCounts()) {
|
||||
if (typesRoot.showCounts) {
|
||||
//only show "(counting...)" the first time, otherwise it is distracting.
|
||||
setDisplayName(getDisplayNameBase() + ((childCount < 0) ? Bundle.FileTypes_bgCounting_placeholder()
|
||||
: ("(" + childCount + ")"))); //NON-NLS
|
||||
@ -239,8 +257,186 @@ public final class FileTypes implements AutopsyVisitableItem {
|
||||
}
|
||||
}.execute();
|
||||
} else {
|
||||
setDisplayName(getDisplayNameBase() + ((childCount < 0) ? "" : ("(" + childCount + "+)"))); //NON-NLS
|
||||
setDisplayName(getDisplayNameBase() + ((childCount < 0) ? "" : (" (" + childCount + "+)"))); //NON-NLS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class that is used as a key by NetBeans for creating result nodes. This
|
||||
* is a wrapper around a Content object and is being put in place as an
|
||||
* optimization to avoid the Content.hashCode() implementation which issues
|
||||
* a database query to get the number of children when determining whether 2
|
||||
* Content objects represent the same thing. TODO: This is a temporary
|
||||
* solution that can hopefully be removed once we address the issue of
|
||||
* determining how many children a Content has (JIRA-2823).
|
||||
*/
|
||||
static class FileTypesKey implements Content {
|
||||
|
||||
private final Content content;
|
||||
|
||||
public FileTypesKey(Content content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final FileTypesKey other = (FileTypesKey) obj;
|
||||
|
||||
return this.content.getId() == other.content.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 7;
|
||||
hash = 101 * hash + (int)(this.content.getId() ^ (this.content.getId() >>> 32));
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(SleuthkitItemVisitor<T> v) {
|
||||
return content.accept(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] buf, long offset, long len) throws TskCoreException {
|
||||
return content.read(buf, offset, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
content.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSize() {
|
||||
return content.getSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(ContentVisitor<T> v) {
|
||||
return content.accept(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return content.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniquePath() throws TskCoreException {
|
||||
return content.getUniquePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return content.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Content getDataSource() throws TskCoreException {
|
||||
return content.getDataSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Content> getChildren() throws TskCoreException {
|
||||
return content.getChildren();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasChildren() throws TskCoreException {
|
||||
return content.hasChildren();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChildrenCount() throws TskCoreException {
|
||||
return content.getChildrenCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Content getParent() throws TskCoreException {
|
||||
return content.getParent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> getChildrenIds() throws TskCoreException {
|
||||
return content.getChildrenIds();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlackboardArtifact newArtifact(int artifactTypeID) throws TskCoreException {
|
||||
return content.newArtifact(artifactTypeID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlackboardArtifact newArtifact(BlackboardArtifact.ARTIFACT_TYPE type) throws TskCoreException {
|
||||
return content.newArtifact(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<BlackboardArtifact> getArtifacts(String artifactTypeName) throws TskCoreException {
|
||||
return content.getArtifacts(artifactTypeName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlackboardArtifact getGenInfoArtifact() throws TskCoreException {
|
||||
return content.getGenInfoArtifact();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlackboardArtifact getGenInfoArtifact(boolean create) throws TskCoreException {
|
||||
return content.getGenInfoArtifact(create);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<BlackboardAttribute> getGenInfoAttributes(BlackboardAttribute.ATTRIBUTE_TYPE attr_type) throws TskCoreException {
|
||||
return content.getGenInfoAttributes(attr_type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<BlackboardArtifact> getArtifacts(int artifactTypeID) throws TskCoreException {
|
||||
return content.getArtifacts(artifactTypeID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<BlackboardArtifact> getArtifacts(BlackboardArtifact.ARTIFACT_TYPE type) throws TskCoreException {
|
||||
return content.getArtifacts(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<BlackboardArtifact> getAllArtifacts() throws TskCoreException {
|
||||
return content.getAllArtifacts();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getHashSetNames() throws TskCoreException {
|
||||
return content.getHashSetNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getArtifactsCount(String artifactTypeName) throws TskCoreException {
|
||||
return content.getArtifactsCount(artifactTypeName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getArtifactsCount(int artifactTypeID) throws TskCoreException {
|
||||
return content.getArtifactsCount(artifactTypeID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getArtifactsCount(BlackboardArtifact.ARTIFACT_TYPE type) throws TskCoreException {
|
||||
return content.getArtifactsCount(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getAllArtifactsCount() throws TskCoreException {
|
||||
return content.getAllArtifactsCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-17 Basis Technology Corp.
|
||||
* Copyright 2011-2017 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -24,7 +24,10 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
@ -34,7 +37,9 @@ import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesKey;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
@ -87,7 +92,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
||||
*/
|
||||
try {
|
||||
Case.getCurrentCase();
|
||||
typesRoot.shouldShowCounts();
|
||||
typesRoot.updateShowCounts();
|
||||
update();
|
||||
} catch (IllegalStateException notUsed) {
|
||||
/**
|
||||
@ -147,8 +152,9 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
||||
* provides updates on events
|
||||
*/
|
||||
private FileTypesByExtNode(SleuthkitCase skCase, FileTypesByExtension.RootFilter filter, FileTypesByExtObservable o) {
|
||||
|
||||
super(Children.create(new FileTypesByExtNodeChildren(skCase, filter, o), true),
|
||||
Lookups.singleton(filter == null ? FNAME : filter.getName()));
|
||||
Lookups.singleton(filter == null ? FNAME : filter.getDisplayName()));
|
||||
this.filter = filter;
|
||||
|
||||
// root node of tree
|
||||
@ -157,7 +163,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
||||
super.setDisplayName(FNAME);
|
||||
} // sub-node in file tree (i.e. documents, exec, etc.)
|
||||
else {
|
||||
super.setName(filter.getName());
|
||||
super.setName(filter.getDisplayName());
|
||||
super.setDisplayName(filter.getDisplayName());
|
||||
}
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png"); //NON-NLS
|
||||
@ -181,7 +187,16 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
||||
ss = Sheet.createPropertiesSet();
|
||||
s.put(ss);
|
||||
}
|
||||
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.name.name"), NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.name.displayName"), NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.name.desc"), getName()));
|
||||
if (filter != null && (filter.equals(FileTypesByExtension.RootFilter.TSK_DOCUMENT_FILTER) || filter.equals(FileTypesByExtension.RootFilter.TSK_EXECUTABLE_FILTER))) {
|
||||
String extensions = "";
|
||||
for (String ext : filter.getFilter()) {
|
||||
extensions += "'" + ext + "', ";
|
||||
}
|
||||
extensions = extensions.substring(0, extensions.lastIndexOf(','));
|
||||
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.fileExt.name"), NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.fileExt.displayName"), NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.fileExt.desc"), extensions));
|
||||
} else {
|
||||
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.name.name"), NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.name.displayName"), NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.name.desc"), getDisplayName()));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@ -272,7 +287,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
||||
super(typesRoot, Children.create(new FileExtensionNodeChildren(filter, skCase, o), true),
|
||||
Lookups.singleton(filter.getDisplayName()));
|
||||
this.filter = filter;
|
||||
setName(filter.getName());
|
||||
super.setName(filter.getDisplayName());
|
||||
updateDisplayName();
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-filter-icon.png"); //NON-NLS
|
||||
|
||||
@ -330,24 +345,43 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
||||
}
|
||||
}
|
||||
|
||||
private static String createQuery(FileTypesByExtension.SearchFilterInterface filter) {
|
||||
StringBuilder query = new StringBuilder();
|
||||
query.append("(dir_type = ").append(TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue()).append(")"); //NON-NLS
|
||||
if (UserPreferences.hideKnownFilesInViewsTree()) {
|
||||
query.append(" AND (known IS NULL OR known != ").append(TskData.FileKnown.KNOWN.getFileKnownValue()).append(")"); //NON-NLS
|
||||
private String createQuery(FileTypesByExtension.SearchFilterInterface filter) {
|
||||
if (filter.getFilter().isEmpty()) {
|
||||
// We should never be given a search filter without extensions
|
||||
// but if we are it is clearly a programming error so we throw
|
||||
// an IllegalArgumentException.
|
||||
throw new IllegalArgumentException("Empty filter list passed to createQuery()"); // NON-NLS
|
||||
}
|
||||
query.append(" AND (NULL"); //NON-NLS
|
||||
for (String s : filter.getFilter()) {
|
||||
query.append(" OR LOWER(name) LIKE LOWER('%").append(s).append("')"); //NON-NLS
|
||||
|
||||
String query = "(dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + ")"
|
||||
+ (UserPreferences.hideKnownFilesInViewsTree() ? " AND (known IS NULL OR known != "
|
||||
+ TskData.FileKnown.KNOWN.getFileKnownValue() + ")" : " ")
|
||||
+ " AND (NULL "; //NON-NLS
|
||||
|
||||
if (skCase.getDatabaseType().equals(TskData.DbType.POSTGRESQL)) {
|
||||
// For PostgreSQL we get a more efficient query by using builtin
|
||||
// regular expression support and or'ing all extensions. We also
|
||||
// escape the dot at the beginning of the extension.
|
||||
// We will end up with a query that looks something like this:
|
||||
// OR LOWER(name) ~ '(\.zip|\.rar|\.7zip|\.cab|\.jar|\.cpio|\.ar|\.gz|\.tgz|\.bz2)$')
|
||||
query += "OR LOWER(name) ~ '(\\";
|
||||
query += StringUtils.join(filter.getFilter().stream()
|
||||
.map(String::toLowerCase).collect(Collectors.toList()), "|\\");
|
||||
query += ")$'";
|
||||
} else {
|
||||
for (String s : filter.getFilter()) {
|
||||
query += "OR LOWER(name) LIKE '%" + s.toLowerCase() + "'"; // NON-NLS
|
||||
}
|
||||
}
|
||||
query.append(')');
|
||||
return query.toString();
|
||||
|
||||
query += ')';
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Child node factory for a specific file type - does the database query.
|
||||
*/
|
||||
private static class FileExtensionNodeChildren extends ChildFactory.Detachable<Content> implements Observer {
|
||||
private class FileExtensionNodeChildren extends ChildFactory.Detachable<FileTypesKey> implements Observer {
|
||||
|
||||
private final SleuthkitCase skCase;
|
||||
private final FileTypesByExtension.SearchFilterInterface filter;
|
||||
@ -387,9 +421,10 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<Content> list) {
|
||||
protected boolean createKeys(List<FileTypesKey> list) {
|
||||
try {
|
||||
list.addAll(skCase.findAllFilesWhere(createQuery(filter)));
|
||||
list.addAll(skCase.findAllFilesWhere(createQuery(filter))
|
||||
.stream().map(f -> new FileTypesKey(f)).collect(Collectors.toList()));
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Couldn't get search results", ex); //NON-NLS
|
||||
}
|
||||
@ -397,7 +432,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(Content key) {
|
||||
protected Node createNodeForKey(FileTypesKey key) {
|
||||
return key.accept(new FileTypes.FileNodeCreationVisitor());
|
||||
}
|
||||
}
|
||||
@ -419,10 +454,10 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
||||
FileTypeExtensions.getArchiveExtensions()),
|
||||
TSK_DOCUMENT_FILTER(3, "TSK_DOCUMENT_FILTER", //NON-NLS
|
||||
NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskDocumentFilter.text"),
|
||||
Arrays.asList(".doc", ".docx", ".pdf", ".xls", ".rtf", ".txt")), //NON-NLS
|
||||
Arrays.asList(".htm", ".html", ".doc", ".docx", ".odt", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".rtf")), //NON-NLS
|
||||
TSK_EXECUTABLE_FILTER(3, "TSK_EXECUTABLE_FILTER", //NON-NLS
|
||||
NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskExecFilter.text"),
|
||||
Arrays.asList(".exe", ".dll", ".bat", ".cmd", ".com")); //NON-NLS
|
||||
FileTypeExtensions.getExecutableExtensions()); //NON-NLS
|
||||
|
||||
private final int id;
|
||||
private final String name;
|
||||
|
@ -30,16 +30,20 @@ import java.util.Map;
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import static org.sleuthkit.autopsy.core.UserPreferences.hideKnownFilesInViewsTree;
|
||||
import static org.sleuthkit.autopsy.core.UserPreferences.hideSlackFilesInViewsTree;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesKey;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
@ -55,6 +59,7 @@ import org.sleuthkit.datamodel.TskData;
|
||||
public final class FileTypesByMimeType extends Observable implements AutopsyVisitableItem {
|
||||
|
||||
private final static Logger logger = Logger.getLogger(FileTypesByMimeType.class.getName());
|
||||
|
||||
private final SleuthkitCase skCase;
|
||||
/**
|
||||
* The nodes of this tree will be determined dynamically by the mimetypes
|
||||
@ -62,36 +67,53 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
|
||||
* type as the key and a Map, from media subtype to count, as the value.
|
||||
*/
|
||||
private final HashMap<String, Map<String, Long>> existingMimeTypeCounts = new HashMap<>();
|
||||
private static final Logger LOGGER = Logger.getLogger(FileTypesByMimeType.class.getName());
|
||||
/**
|
||||
* Root of the File Types tree. Used to provide single answer to question:
|
||||
* Should the child counts be shown next to the nodes?
|
||||
*/
|
||||
private final FileTypes typesRoot;
|
||||
|
||||
private void removeListeners() {
|
||||
deleteObservers();
|
||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||
Case.removePropertyChangeListener(pcl);
|
||||
}
|
||||
/*
|
||||
/**
|
||||
* The pcl is in the class because it has the easiest mechanisms to add and
|
||||
* remove itself during its life cycles.
|
||||
*/
|
||||
private final PropertyChangeListener pcl;
|
||||
|
||||
/**
|
||||
* Performs the query on the database to get all distinct MIME types of
|
||||
* files in it, and populate the hashmap with those results.
|
||||
* Create the base expression used as the where clause in the queries for
|
||||
* files by mime type. Filters out certain kinds of files and directories,
|
||||
* and known/slack files based on user preferences.
|
||||
*
|
||||
* @return The base expression to be used in the where clause of queries for
|
||||
* files by mime type.
|
||||
*/
|
||||
private void populateHashMap() {
|
||||
String query = "SELECT mime_type,count(*) as count from tsk_files "
|
||||
+ " where mime_type IS NOT null "
|
||||
+ " AND dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue()
|
||||
static private String createBaseWhereExpr() {
|
||||
return "(dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + ")"
|
||||
+ " AND (type IN ("
|
||||
+ TskData.TSK_DB_FILES_TYPE_ENUM.FS.ordinal() + ","
|
||||
+ TskData.TSK_DB_FILES_TYPE_ENUM.CARVED.ordinal() + ","
|
||||
+ TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.ordinal() + ","
|
||||
+ TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal()
|
||||
+ ((UserPreferences.hideSlackFilesInViewsTree()) ? ""
|
||||
: ("," + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal()))
|
||||
+ "))" + " GROUP BY mime_type";
|
||||
+ (hideSlackFilesInViewsTree() ? "" : ("," + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal()))
|
||||
+ "))"
|
||||
+ (hideKnownFilesInViewsTree() ? (" AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")") : "");
|
||||
}
|
||||
|
||||
private void removeListeners() {
|
||||
deleteObservers();
|
||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||
Case.removePropertyChangeListener(pcl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the query on the database to get all distinct MIME types of
|
||||
* files in it, and populate the hashmap with those results.
|
||||
*/
|
||||
private void populateHashMap() {
|
||||
String query = "SELECT mime_type, count(*) AS count FROM tsk_files "
|
||||
+ " WHERE mime_type IS NOT null "
|
||||
+ " AND " + createBaseWhereExpr()
|
||||
+ " GROUP BY mime_type";
|
||||
synchronized (existingMimeTypeCounts) {
|
||||
existingMimeTypeCounts.clear();
|
||||
|
||||
@ -114,7 +136,7 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
|
||||
}
|
||||
}
|
||||
} catch (TskCoreException | SQLException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to populate File Types by MIME Type tree view from DB: ", ex); //NON-NLS
|
||||
logger.log(Level.SEVERE, "Unable to populate File Types by MIME Type tree view from DB: ", ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,7 +160,7 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
|
||||
*/
|
||||
try {
|
||||
Case.getCurrentCase();
|
||||
typesRoot.shouldShowCounts();
|
||||
typesRoot.updateShowCounts();
|
||||
populateHashMap();
|
||||
} catch (IllegalStateException notUsed) {
|
||||
/**
|
||||
@ -187,11 +209,12 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
|
||||
*/
|
||||
class ByMimeTypeNode extends DisplayableItemNode {
|
||||
|
||||
@NbBundle.Messages("FileTypesByMimeType.name.text=By MIME Type")
|
||||
@NbBundle.Messages({"FileTypesByMimeType.name.text=By MIME Type"})
|
||||
|
||||
final String NAME = Bundle.FileTypesByMimeType_name_text();
|
||||
|
||||
ByMimeTypeNode() {
|
||||
super(Children.create(new ByMimeTypeNodeChildren(), true));
|
||||
super(Children.create(new ByMimeTypeNodeChildren(), true), Lookups.singleton(Bundle.FileTypesByMimeType_name_text()));
|
||||
super.setName(NAME);
|
||||
super.setDisplayName(NAME);
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png");
|
||||
@ -259,8 +282,12 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
|
||||
*/
|
||||
class MediaTypeNode extends DisplayableItemNode {
|
||||
|
||||
@NbBundle.Messages({"FileTypesByMimeTypeNode.createSheet.mediaType.name=Type",
|
||||
"FileTypesByMimeTypeNode.createSheet.mediaType.displayName=Type",
|
||||
"FileTypesByMimeTypeNode.createSheet.mediaType.desc=no description"})
|
||||
|
||||
MediaTypeNode(String name) {
|
||||
super(Children.create(new MediaTypeNodeChildren(name), true));
|
||||
super(Children.create(new MediaTypeNodeChildren(name), true), Lookups.singleton(name));
|
||||
setName(name);
|
||||
setDisplayName(name);
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png");
|
||||
@ -276,6 +303,18 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet s = super.createSheet();
|
||||
Sheet.Set ss = s.get(Sheet.PROPERTIES);
|
||||
if (ss == null) {
|
||||
ss = Sheet.createPropertiesSet();
|
||||
s.put(ss);
|
||||
}
|
||||
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByMimeTypeNode.createSheet.mediaType.name"), NbBundle.getMessage(this.getClass(), "FileTypesByMimeTypeNode.createSheet.mediaType.displayName"), NbBundle.getMessage(this.getClass(), "FileTypesByMimeTypeNode.createSheet.mediaType.desc"), getDisplayName()));
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
@ -316,19 +355,25 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Node which represents the media sub type in the By MIME type tree, the
|
||||
* media subtype is the portion of the MIME type following the /.
|
||||
*/
|
||||
class MediaSubTypeNode extends FileTypes.BGCountUpdatingNode {
|
||||
|
||||
@NbBundle.Messages({"FileTypesByMimeTypeNode.createSheet.mediaSubtype.name=Subtype",
|
||||
"FileTypesByMimeTypeNode.createSheet.mediaSubtype.displayName=Subtype",
|
||||
"FileTypesByMimeTypeNode.createSheet.mediaSubtype.desc=no description"})
|
||||
private final String mimeType;
|
||||
private final String subType;
|
||||
|
||||
private MediaSubTypeNode(String mimeType) {
|
||||
super(typesRoot, Children.create(new MediaSubTypeNodeChildren(mimeType), true));
|
||||
super(typesRoot, Children.create(new MediaSubTypeNodeChildren(mimeType), true), Lookups.singleton(mimeType));
|
||||
this.mimeType = mimeType;
|
||||
this.subType = StringUtils.substringAfter(mimeType, "/");
|
||||
super.setName(mimeType);
|
||||
super.setDisplayName(subType);
|
||||
updateDisplayName();
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-filter-icon.png"); //NON-NLS
|
||||
|
||||
addObserver(this);
|
||||
}
|
||||
|
||||
@ -347,6 +392,17 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
|
||||
public <T> T accept(DisplayableItemNodeVisitor< T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet s = super.createSheet();
|
||||
Sheet.Set ss = s.get(Sheet.PROPERTIES);
|
||||
if (ss == null) {
|
||||
ss = Sheet.createPropertiesSet();
|
||||
s.put(ss);
|
||||
}
|
||||
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByMimeTypeNode.createSheet.mediaSubtype.name"), NbBundle.getMessage(this.getClass(), "FileTypesByMimeTypeNode.createSheet.mediaSubtype.displayName"), NbBundle.getMessage(this.getClass(), "FileTypesByMimeTypeNode.createSheet.mediaSubtype.desc"), getDisplayName()));
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemType() {
|
||||
@ -369,39 +425,12 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the portion of the query following WHERE for a query of the
|
||||
* database for each file which matches the complete MIME type represented
|
||||
* by this node. Matches against the mime_type column in tsk_files.
|
||||
*
|
||||
* @param mimeType - the complete mimetype of the file mediatype/subtype
|
||||
*
|
||||
* @return query.toString - portion of SQL query which will follow a WHERE
|
||||
* clause.
|
||||
*/
|
||||
static private String createQuery(String mimeType) {
|
||||
StringBuilder query = new StringBuilder();
|
||||
query.append("(dir_type = ").append(TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue()).append(")"); //NON-NLS
|
||||
query.append(" AND (type IN (").append(TskData.TSK_DB_FILES_TYPE_ENUM.FS.ordinal()).append(","); //NON-NLS
|
||||
query.append(TskData.TSK_DB_FILES_TYPE_ENUM.CARVED.ordinal()).append(",");
|
||||
query.append(TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.ordinal()).append(",");
|
||||
if (!UserPreferences.hideSlackFilesInViewsTree()) {
|
||||
query.append(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal()).append(",");
|
||||
}
|
||||
query.append(TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal()).append("))");
|
||||
if (UserPreferences.hideKnownFilesInViewsTree()) {
|
||||
query.append(" AND (known IS NULL OR known != ").append(TskData.FileKnown.KNOWN.getFileKnownValue()).append(")"); //NON-NLS
|
||||
}
|
||||
query.append(" AND mime_type = '").append(mimeType).append("'"); //NON-NLS
|
||||
return query.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory for populating the contents of the Media Sub Type Node with the
|
||||
* files that match MimeType which is represented by this position in the
|
||||
* tree.
|
||||
*/
|
||||
private class MediaSubTypeNodeChildren extends ChildFactory.Detachable<Content> implements Observer {
|
||||
private class MediaSubTypeNodeChildren extends ChildFactory.Detachable<FileTypesKey> implements Observer {
|
||||
|
||||
private final String mimeType;
|
||||
|
||||
@ -411,23 +440,13 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
|
||||
this.mimeType = mimeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the createQuery method to complete the query, Select * from
|
||||
* tsk_files WHERE. The results from the database will contain the files
|
||||
* which match this mime type and their information.
|
||||
*
|
||||
* @param list - will contain all files and their attributes from the
|
||||
* tsk_files table where mime_type matches the one specified
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
@Override
|
||||
protected boolean createKeys(List<Content> list) {
|
||||
protected boolean createKeys(List<FileTypesKey> list) {
|
||||
try {
|
||||
List<AbstractFile> files = skCase.findAllFilesWhere(createQuery(mimeType));
|
||||
list.addAll(files);
|
||||
list.addAll(skCase.findAllFilesWhere(createBaseWhereExpr() + " AND mime_type = '" + mimeType + "'")
|
||||
.stream().map(f -> new FileTypesKey(f)).collect(Collectors.toList())); //NON-NLS
|
||||
} catch (TskCoreException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Couldn't get search results", ex); //NON-NLS
|
||||
logger.log(Level.SEVERE, "Couldn't get search results", ex); //NON-NLS
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -437,19 +456,9 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
|
||||
refresh(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the content to populate the Directory Listing Table view for
|
||||
* each file
|
||||
*
|
||||
* @param key
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected Node createNodeForKey(Content key) {
|
||||
protected Node createNodeForKey(FileTypesKey key) {
|
||||
return key.accept(new FileTypes.FileNodeCreationVisitor());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -24,7 +24,6 @@ import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
@ -33,6 +32,7 @@ import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
@ -95,6 +95,10 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
+ " OR attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID()//NON-NLS
|
||||
+ ")"; //NON-NLS
|
||||
|
||||
static private boolean isOnlyDefaultInstance(List<String> instances) {
|
||||
return (instances.size() == 1) && (instances.get(0).equals(DEFAULT_INSTANCE_NAME));
|
||||
}
|
||||
|
||||
public KeywordHits(SleuthkitCase skCase) {
|
||||
this.skCase = skCase;
|
||||
keywordResults = new KeywordResults();
|
||||
@ -265,7 +269,6 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
addRegExpToList(listMap, reg, word, id);
|
||||
}
|
||||
} else {//single term
|
||||
|
||||
if ("1".equals(kwType) || reg == null) { //literal, substring or exact
|
||||
/*
|
||||
* Substring, treated same as exact match. "1" is
|
||||
@ -626,9 +629,8 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
List<String> instances = keywordResults.getKeywordInstances(setName, keyword);
|
||||
// is this an exact/substring match (i.e. did we use the DEFAULT name)?
|
||||
return instances.size() == 1 && instances.get(0).equals(DEFAULT_INSTANCE_NAME);
|
||||
return isOnlyDefaultInstance(keywordResults.getKeywordInstances(setName, keyword));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -661,7 +663,6 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -706,7 +707,6 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
|
||||
private final String keyword;
|
||||
private final String setName;
|
||||
private final Map<RegExpInstanceKey, DisplayableItemNode> nodesMap = new HashMap<>();
|
||||
|
||||
private RegExpInstancesFactory(String setName, String keyword) {
|
||||
super();
|
||||
@ -720,29 +720,20 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
// The keys are different depending on what we are displaying.
|
||||
// regexp get another layer to show instances.
|
||||
// Exact/substring matches don't.
|
||||
if ((instances.size() == 1) && (instances.get(0).equals(DEFAULT_INSTANCE_NAME))) {
|
||||
for (Long id : keywordResults.getArtifactIds(setName, keyword, DEFAULT_INSTANCE_NAME)) {
|
||||
RegExpInstanceKey key = new RegExpInstanceKey(id);
|
||||
nodesMap.computeIfAbsent(key, k -> createNode(k));
|
||||
list.add(key);
|
||||
}
|
||||
if (isOnlyDefaultInstance(instances)) {
|
||||
list.addAll(keywordResults.getArtifactIds(setName, keyword, DEFAULT_INSTANCE_NAME).stream()
|
||||
.map(RegExpInstanceKey::new)
|
||||
.collect(Collectors.toList()));
|
||||
} else {
|
||||
for (String instance : instances) {
|
||||
RegExpInstanceKey key = new RegExpInstanceKey(instance);
|
||||
nodesMap.computeIfAbsent(key, k -> createNode(k));
|
||||
list.add(key);
|
||||
}
|
||||
|
||||
list.addAll(instances.stream()
|
||||
.map(RegExpInstanceKey::new)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(RegExpInstanceKey key) {
|
||||
return nodesMap.get(key);
|
||||
}
|
||||
|
||||
private DisplayableItemNode createNode(RegExpInstanceKey key) {
|
||||
if (key.isRegExp()) {
|
||||
return new RegExpInstanceNode(setName, keyword, key.getRegExpKey());
|
||||
} else {
|
||||
@ -750,6 +741,7 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
return createBlackboardArtifactNode(key.getIdKey());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -884,7 +876,6 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
private final String keyword;
|
||||
private final String setName;
|
||||
private final String instance;
|
||||
private final Map<Long, BlackboardArtifactNode> nodesMap = new HashMap<>();
|
||||
|
||||
private HitsFactory(String setName, String keyword, String instance) {
|
||||
super();
|
||||
@ -895,16 +886,13 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<Long> list) {
|
||||
for (Long id : keywordResults.getArtifactIds(setName, keyword, instance)) {
|
||||
nodesMap.computeIfAbsent(id, i -> createBlackboardArtifactNode(i));
|
||||
list.add(id);
|
||||
}
|
||||
list.addAll(keywordResults.getArtifactIds(setName, keyword, instance));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(Long artifactId) {
|
||||
return nodesMap.get(artifactId);
|
||||
return createBlackboardArtifactNode(artifactId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -417,7 +417,9 @@ final class ExtractUnallocAction extends AbstractAction {
|
||||
try {
|
||||
List<LayoutFile> lflst = new ArrayList<>();
|
||||
for (Content layout : vd.getChildren()) {
|
||||
lflst.add((LayoutFile) layout);
|
||||
if(layout instanceof LayoutFile){
|
||||
lflst.add((LayoutFile) layout);
|
||||
}
|
||||
}
|
||||
return lflst;
|
||||
} catch (TskCoreException tce) {
|
||||
|
@ -51,6 +51,7 @@ final class GetFilesCountVisitor extends ContentVisitor.Default<Long> {
|
||||
queryB.append(") )");
|
||||
queryB.append(" AND ( (meta_type = ").append(TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); //NON-NLS
|
||||
queryB.append(") OR (meta_type = ").append(TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()); //NON-NLS
|
||||
queryB.append(") OR (meta_type = ").append(TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue()); //NON-NLS
|
||||
queryB.append(") OR (meta_type = ").append(TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT.getValue()); //NON-NLS
|
||||
queryB.append(" AND (name != '.') AND (name != '..')"); //NON-NLS
|
||||
queryB.append(") )");
|
||||
|
@ -537,10 +537,12 @@ public final class FilesSet implements Serializable {
|
||||
case FILES:
|
||||
return file.isFile();
|
||||
case DIRECTORIES:
|
||||
return file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR;
|
||||
return file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR
|
||||
|| file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR;
|
||||
case FILES_AND_DIRECTORIES:
|
||||
return file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG
|
||||
|| file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR;
|
||||
|| file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR
|
||||
|| file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR;
|
||||
case ALL:
|
||||
return true; //Effectively ignores the metatype condition when All is selected.
|
||||
default:
|
||||
|
@ -23,17 +23,13 @@ import java.io.FilenameFilter;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.CaseMetadata;
|
||||
import org.sleuthkit.autopsy.casemodule.GeneralFilter;
|
||||
|
||||
final class PathUtils {
|
||||
|
||||
private static final List<String> CASE_METADATA_FILE_EXTS = Arrays.asList(new String[]{CaseMetadata.getFileExtension()});
|
||||
private static final GeneralFilter caseMetadataFileFilter = new GeneralFilter(CASE_METADATA_FILE_EXTS, "Autopsy Case File");
|
||||
private final static String CASE_METADATA_EXT = CaseMetadata.getFileExtension();
|
||||
|
||||
/**
|
||||
* Searches a given folder for the most recently modified case folder for a
|
||||
@ -83,34 +79,6 @@ final class PathUtils {
|
||||
return caseFolderPaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not there is a case metadata file in a given
|
||||
* folder.
|
||||
*
|
||||
* @param folderPath Path to the folder to search.
|
||||
*
|
||||
* @return True or false.
|
||||
*/
|
||||
static boolean hasCaseMetadataFile(Path folderPath) {
|
||||
/**
|
||||
* TODO: If need be, this can be rewritten without the FilenameFilter so
|
||||
* that it does not necessarily visit every file in the folder.
|
||||
*/
|
||||
File folder = folderPath.toFile();
|
||||
if (!folder.isDirectory()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String[] caseDataFiles = folder.list((File folder1, String fileName) -> {
|
||||
File file = new File(folder1, fileName);
|
||||
if (file.isFile()) {
|
||||
return caseMetadataFileFilter.accept(file);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return caseDataFiles.length != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the case name from a case folder path.
|
||||
*
|
||||
@ -141,6 +109,12 @@ final class PathUtils {
|
||||
return Paths.get(caseFoldersPath.toString(), folderName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Supress creation of instances of this class.
|
||||
*/
|
||||
private PathUtils() {
|
||||
}
|
||||
|
||||
private static class CaseFolderFilter implements FilenameFilter {
|
||||
|
||||
private final String caseName;
|
||||
@ -152,28 +126,37 @@ final class PathUtils {
|
||||
@Override
|
||||
public boolean accept(File folder, String fileName) {
|
||||
File file = new File(folder, fileName);
|
||||
if (file.isDirectory() && fileName.length() > TimeStampUtils.getTimeStampLength()) {
|
||||
Path filePath = Paths.get(file.getPath());
|
||||
if (fileName.length() > TimeStampUtils.getTimeStampLength() && file.isDirectory()) {
|
||||
if (TimeStampUtils.endsWithTimeStamp(fileName)) {
|
||||
if (null != caseName) {
|
||||
String fileNamePrefix = fileName.substring(0, fileName.length() - TimeStampUtils.getTimeStampLength());
|
||||
if (fileNamePrefix.equals(caseName)) {
|
||||
return hasCaseMetadataFile(filePath);
|
||||
return hasCaseMetadataFile(file);
|
||||
}
|
||||
} else {
|
||||
return hasCaseMetadataFile(filePath);
|
||||
return hasCaseMetadataFile(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* Determines whether or not there is a case metadata file in a given
|
||||
* folder.
|
||||
*
|
||||
* @param folder The file object representing the folder to search.
|
||||
*
|
||||
* @return True or false.
|
||||
*/
|
||||
private static boolean hasCaseMetadataFile(File folder) {
|
||||
for (File file : folder.listFiles()) {
|
||||
if (file.getName().toLowerCase().endsWith(CASE_METADATA_EXT) && file.isFile()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Supress creation of instances of this class.
|
||||
*/
|
||||
private PathUtils() {
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2015 Basis Technology Corp.
|
||||
* Copyright 2015-2017 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -174,6 +174,7 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel {
|
||||
}
|
||||
|
||||
validateSettings();
|
||||
enableOptionsBasedOnMode(getModeFromRadioButtons());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -306,10 +307,13 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel {
|
||||
*/
|
||||
boolean valid() {
|
||||
|
||||
if (!cbJoinAutoIngestCluster.isSelected()) {
|
||||
if (!cbJoinAutoIngestCluster.isSelected()) { //hide the invalid field warnings when in stand alone mode
|
||||
jLabelInvalidImageFolder.setVisible(false);
|
||||
jLabelInvalidResultsFolder.setVisible(false);
|
||||
sharedSettingsErrorTextField.setVisible(false);
|
||||
configButtonErrorTextField.setText("");
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean isValidNodePanel = true;
|
||||
|
||||
switch (getModeFromRadioButtons()) {
|
||||
@ -326,6 +330,7 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel {
|
||||
}
|
||||
break;
|
||||
case REVIEW:
|
||||
jLabelInvalidImageFolder.setVisible(false);
|
||||
if (!validateResultsPath()) {
|
||||
isValidNodePanel = false;
|
||||
}
|
||||
@ -596,23 +601,24 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel {
|
||||
|
||||
private void enableOptionsBasedOnMode(OptionsUiMode mode) {
|
||||
if (mode != OptionsUiMode.DOWNLOADING_CONFIGURATION) {
|
||||
jRadioButtonAutomated.setEnabled(cbJoinAutoIngestCluster.isSelected());
|
||||
jRadioButtonReview.setEnabled(cbJoinAutoIngestCluster.isSelected());
|
||||
boolean nonMasterSharedConfig = !masterNodeCheckBox.isSelected() && sharedConfigCheckbox.isSelected();
|
||||
jRadioButtonAutomated.setEnabled(cbJoinAutoIngestCluster.isSelected() && !sharedConfigCheckbox.isSelected());
|
||||
jRadioButtonReview.setEnabled(cbJoinAutoIngestCluster.isSelected() && !sharedConfigCheckbox.isSelected());
|
||||
|
||||
jLabelSelectInputFolder.setEnabled(mode == OptionsUiMode.AIM);
|
||||
inputPathTextField.setEnabled(mode == OptionsUiMode.AIM);
|
||||
browseInputFolderButton.setEnabled(mode == OptionsUiMode.AIM);
|
||||
jLabelSelectInputFolder.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig);
|
||||
inputPathTextField.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig);
|
||||
browseInputFolderButton.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig);
|
||||
|
||||
jLabelSelectOutputFolder.setEnabled(mode == OptionsUiMode.AIM || mode == OptionsUiMode.REVIEW);
|
||||
outputPathTextField.setEnabled(mode == OptionsUiMode.AIM || mode == OptionsUiMode.REVIEW);
|
||||
browseOutputFolderButton.setEnabled(mode == OptionsUiMode.AIM || mode == OptionsUiMode.REVIEW);
|
||||
jLabelSelectOutputFolder.setEnabled((mode == OptionsUiMode.AIM && !nonMasterSharedConfig) || mode == OptionsUiMode.REVIEW);
|
||||
outputPathTextField.setEnabled((mode == OptionsUiMode.AIM && !nonMasterSharedConfig) || mode == OptionsUiMode.REVIEW);
|
||||
browseOutputFolderButton.setEnabled((mode == OptionsUiMode.AIM && !nonMasterSharedConfig) || mode == OptionsUiMode.REVIEW);
|
||||
|
||||
jPanelSharedConfig.setEnabled(mode == OptionsUiMode.AIM);
|
||||
|
||||
jPanelIngestSettings.setEnabled(mode == OptionsUiMode.AIM);
|
||||
bnEditIngestSettings.setEnabled(mode == OptionsUiMode.AIM);
|
||||
bnAdvancedSettings.setEnabled(mode == OptionsUiMode.AIM);
|
||||
bnLogging.setEnabled(mode == OptionsUiMode.AIM);
|
||||
jPanelIngestSettings.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig);
|
||||
bnEditIngestSettings.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig);
|
||||
bnAdvancedSettings.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig);
|
||||
bnLogging.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig);
|
||||
jPanelSharedConfig.setEnabled(mode == OptionsUiMode.AIM);
|
||||
sharedConfigCheckbox.setEnabled(mode == OptionsUiMode.AIM);
|
||||
masterNodeCheckBox.setEnabled(mode == OptionsUiMode.AIM && sharedConfigCheckbox.isSelected());
|
||||
@ -1389,12 +1395,7 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel {
|
||||
|
||||
void setEnabledStateForSharedConfiguration() {
|
||||
if (jRadioButtonAutomated.isSelected() && cbJoinAutoIngestCluster.isSelected()) {
|
||||
if (sharedConfigCheckbox.isEnabled() && sharedConfigCheckbox.isSelected()) {
|
||||
setEnabledState(masterNodeCheckBox.isSelected());
|
||||
} else {
|
||||
// If we are in AIM mode and shared config is not enabled, allow this
|
||||
setEnabledState(true);
|
||||
}
|
||||
enableOptionsBasedOnMode(OptionsUiMode.AIM);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,6 @@ AdvancedAutoIngestSettingsPanel.lbSecondsBetweenJobs.toolTipText=A wait time use
|
||||
AdvancedAutoIngestSettingsPanel.tbWarning.text=WARNING: Ensure you know what you are doing before modifying these values. Informed use can improve system performance. Misuse can cause system performance degradation and data loss. Please consult the user guide for details.
|
||||
AdvancedAutoIngestSettingsPanel.threadCountLabel.text=For this computer, a maximum of {0} file ingest threads should be used.
|
||||
AIMIngestSettingsPanel.browseGlobalSettingsButton.text=Browse
|
||||
AIMIngestSettingsPanel.globalSettingsCheckbox.text=Use shared configuration in folder:
|
||||
AIMIngestSettingsPanel.globalSettingsErrorTextField.text=
|
||||
AIMIngestSettingsPanel.globalSettingsTextField.text=
|
||||
AIMIngestSettingsPanel.jButton1.text=Download shared settings
|
||||
@ -33,7 +32,6 @@ AutoIngestSettingsPanel.downloadButton.text=Download Config
|
||||
AutoIngestSettingsPanel.EmptySettingsDirectory=Enter path to settings directory
|
||||
AutoIngestSettingsPanel.ErrorSettingDefaultFolder=Error creating default folder
|
||||
AutoIngestSettingsPanel.FileExportRules.text=File Export Rules
|
||||
AutoIngestSettingsPanel.globalSettingsCheckbox.text=Use shared configuration in folder:
|
||||
AutoIngestSettingsPanel.globalSettingsErrorTextField.text=
|
||||
AutoIngestSettingsPanel.globalSettingsTextField.text=
|
||||
AutoIngestSettingsPanel.ImageDirectoryUnspecified=Shared images folder must be set
|
||||
|
@ -101,7 +101,7 @@ class GlobalEditListPanel extends javax.swing.JPanel implements ListSelectionLis
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Enables and disables buttons on this panel based on the current state.
|
||||
*/
|
||||
@ -125,12 +125,12 @@ class GlobalEditListPanel extends javax.swing.JPanel implements ListSelectionLis
|
||||
}
|
||||
}
|
||||
|
||||
@NbBundle.Messages("GlobalEditListPanel.editKeyword.title=Edit Keyword")
|
||||
@NbBundle.Messages("GlobalEditListPanel.editKeyword.title=Edit Keyword")
|
||||
/**
|
||||
* Adds keywords to a keyword list, returns true if at least one keyword was successfully added and no
|
||||
* duplicates were found.
|
||||
*
|
||||
* @return - true or false
|
||||
* Adds keywords to a keyword list, returns true if at least one keyword was
|
||||
* successfully added and no duplicates were found.
|
||||
*
|
||||
* @return - true or false
|
||||
*/
|
||||
private boolean addKeywordsAction(String existingKeywords, boolean isLiteral, boolean isWholeWord) {
|
||||
String keywordsToRedisplay = existingKeywords;
|
||||
@ -140,7 +140,7 @@ class GlobalEditListPanel extends javax.swing.JPanel implements ListSelectionLis
|
||||
int dupeCount = 0;
|
||||
int badCount = 1; // Default to 1 so we enter the loop the first time
|
||||
|
||||
if (!existingKeywords.isEmpty()){ //if there is an existing keyword then this action was called by the edit button
|
||||
if (!existingKeywords.isEmpty()) { //if there is an existing keyword then this action was called by the edit button
|
||||
dialog.setTitle(NbBundle.getMessage(GlobalEditListPanel.class, "GlobalEditListPanel.editKeyword.title"));
|
||||
}
|
||||
while (badCount > 0) {
|
||||
@ -162,7 +162,7 @@ class GlobalEditListPanel extends javax.swing.JPanel implements ListSelectionLis
|
||||
final Keyword keyword = new Keyword(newWord, !dialog.isKeywordRegex(), dialog.isKeywordExact(), currentKeywordList.getName(), newWord);
|
||||
if (currentKeywordList.hasKeyword(keyword)) {
|
||||
dupeCount++;
|
||||
continue;
|
||||
continue;
|
||||
}
|
||||
|
||||
//check if valid
|
||||
@ -231,8 +231,9 @@ class GlobalEditListPanel extends javax.swing.JPanel implements ListSelectionLis
|
||||
|
||||
/**
|
||||
* Remove one or more keywords from a keyword list.
|
||||
*
|
||||
* @param selectedKeywords the indices of the keywords you would like to delete
|
||||
*
|
||||
* @param selectedKeywords the indices of the keywords you would like to
|
||||
* delete
|
||||
*/
|
||||
private void deleteKeywordAction(int[] selectedKeywords) {
|
||||
tableModel.deleteSelected(selectedKeywords);
|
||||
@ -411,20 +412,15 @@ class GlobalEditListPanel extends javax.swing.JPanel implements ListSelectionLis
|
||||
public void valueChanged(ListSelectionEvent e) {
|
||||
//respond to list selection changes in KeywordSearchListManagementPanel
|
||||
ListSelectionModel listSelectionModel = (ListSelectionModel) e.getSource();
|
||||
currentKeywordList = null;
|
||||
if (!listSelectionModel.isSelectionEmpty()) {
|
||||
int index = listSelectionModel.getMinSelectionIndex();
|
||||
|
||||
listSelectionModel.setSelectionInterval(index, index);
|
||||
XmlKeywordSearchList loader = XmlKeywordSearchList.getCurrent();
|
||||
|
||||
currentKeywordList = loader.getListsL(false).get(index);
|
||||
tableModel.resync();
|
||||
setButtonStates();
|
||||
} else {
|
||||
currentKeywordList = null;
|
||||
tableModel.resync();
|
||||
setButtonStates();
|
||||
if (listSelectionModel.getMinSelectionIndex() == listSelectionModel.getMaxSelectionIndex()) {
|
||||
currentKeywordList = loader.getListsL(false).get(listSelectionModel.getMinSelectionIndex());
|
||||
}
|
||||
}
|
||||
tableModel.resync();
|
||||
setButtonStates();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -46,8 +46,7 @@ final class GlobalListSettingsPanel extends javax.swing.JPanel implements Option
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (KeywordSearchUtil.displayConfirmDialog(NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel1.customizeComponents.title"), NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel1.customizeComponents.body"), KeywordSearchUtil.DIALOG_MESSAGE_TYPE.WARN)) {
|
||||
String toDelete = editListPanel.getCurrentKeywordList().getName();
|
||||
deleteAction(toDelete);
|
||||
deleteAction();
|
||||
listsManagementPanel.resync();
|
||||
}
|
||||
}
|
||||
@ -56,9 +55,8 @@ final class GlobalListSettingsPanel extends javax.swing.JPanel implements Option
|
||||
listsManagementPanel.addRenameButtonActionPerformed(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
String toDelete = editListPanel.getCurrentKeywordList().getName();
|
||||
if (copyAction()) {
|
||||
deleteAction(toDelete);
|
||||
deleteAction();
|
||||
listsManagementPanel.resync();
|
||||
}
|
||||
}
|
||||
@ -83,9 +81,8 @@ final class GlobalListSettingsPanel extends javax.swing.JPanel implements Option
|
||||
*
|
||||
* @param toDelete - the list to delete
|
||||
*/
|
||||
private void deleteAction(String toDelete) {
|
||||
XmlKeywordSearchList deleter = XmlKeywordSearchList.getCurrent();
|
||||
deleter.deleteList(toDelete);
|
||||
private void deleteAction() {
|
||||
listsManagementPanel.deleteSelected();
|
||||
editListPanel.setCurrentKeywordList(null);
|
||||
editListPanel.setButtonStates();
|
||||
listsManagementPanel.setButtonStates();
|
||||
|
@ -102,12 +102,12 @@ class GlobalListsManagementPanel extends javax.swing.JPanel implements OptionsPa
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the dialogue for creating a new keyword list and adds it to the table.
|
||||
* Opens the dialogue for creating a new keyword list and adds it to the
|
||||
* table.
|
||||
*/
|
||||
private void newKeywordListAction() {
|
||||
XmlKeywordSearchList writer = XmlKeywordSearchList.getCurrent();
|
||||
String listName = "";
|
||||
|
||||
|
||||
listName = (String) JOptionPane.showInputDialog(null, NbBundle.getMessage(this.getClass(), "KeywordSearch.newKwListTitle"),
|
||||
NbBundle.getMessage(this.getClass(), "KeywordSearch.newKeywordListMsg"), JOptionPane.PLAIN_MESSAGE, null, null, listName);
|
||||
@ -158,15 +158,19 @@ class GlobalListsManagementPanel extends javax.swing.JPanel implements OptionsPa
|
||||
boolean isIngestRunning = IngestManager.getInstance().isIngestRunning();
|
||||
boolean isListSelected = !listsTable.getSelectionModel().isSelectionEmpty();
|
||||
boolean canEditList = isListSelected && !isIngestRunning;
|
||||
boolean multiSelection = false; //can't rename or copy when multiple lists selected
|
||||
if (isListSelected) {
|
||||
multiSelection = (listsTable.getSelectionModel().getMaxSelectionIndex() != listsTable.getSelectionModel().getMinSelectionIndex());
|
||||
}
|
||||
// items that only need ingest to not be running
|
||||
importButton.setEnabled(!isIngestRunning);
|
||||
|
||||
// items that need an unlocked list w/out ingest running
|
||||
// items that need an unlocked list w/out ingest running
|
||||
deleteListButton.setEnabled(canEditList);
|
||||
renameListButton.setEnabled(canEditList);
|
||||
|
||||
renameListButton.setEnabled(canEditList && !multiSelection);
|
||||
// items that only need a selected list
|
||||
copyListButton.setEnabled(isListSelected);
|
||||
copyListButton.setEnabled(isListSelected && !multiSelection);
|
||||
exportButton.setEnabled(isListSelected);
|
||||
}
|
||||
|
||||
@ -435,13 +439,9 @@ class GlobalListsManagementPanel extends javax.swing.JPanel implements OptionsPa
|
||||
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
|
||||
}//GEN-LAST:event_importButtonActionPerformed
|
||||
private void listsTableKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_listsTableKeyPressed
|
||||
if (evt.getKeyCode() == KeyEvent.VK_DELETE) {
|
||||
int[] selected = listsTable.getSelectedRows();
|
||||
if (selected.length == 0) {
|
||||
return;
|
||||
} else if (KeywordSearchUtil.displayConfirmDialog(NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel1.customizeComponents.title"), NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel1.customizeComponents.body"), KeywordSearchUtil.DIALOG_MESSAGE_TYPE.WARN)) {
|
||||
String listName = (String) listsTable.getModel().getValueAt(selected[0], 0);
|
||||
XmlKeywordSearchList.getCurrent().deleteList(listName);
|
||||
if (evt.getKeyCode() == KeyEvent.VK_DELETE && !IngestManager.getInstance().isIngestRunning() && !listsTable.getSelectionModel().isSelectionEmpty()) {
|
||||
if (KeywordSearchUtil.displayConfirmDialog(NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel1.customizeComponents.title"), NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel1.customizeComponents.body"), KeywordSearchUtil.DIALOG_MESSAGE_TYPE.WARN)) {
|
||||
deleteSelected();
|
||||
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
|
||||
} else {
|
||||
return;
|
||||
@ -492,7 +492,11 @@ class GlobalListsManagementPanel extends javax.swing.JPanel implements OptionsPa
|
||||
XmlKeywordSearchList reader = XmlKeywordSearchList.getCurrent();
|
||||
|
||||
List<KeywordList> toWrite = new ArrayList<>();
|
||||
toWrite.add(reader.getList(listName));
|
||||
|
||||
for (int index : listsTable.getSelectedRows()) {
|
||||
toWrite.add(reader.getList(listsTable.getValueAt(index, 0).toString()));
|
||||
}
|
||||
|
||||
final XmlKeywordSearchList exporter = new XmlKeywordSearchList(fileAbs);
|
||||
boolean written = exporter.saveLists(toWrite);
|
||||
if (written) {
|
||||
@ -541,6 +545,14 @@ class GlobalListsManagementPanel extends javax.swing.JPanel implements OptionsPa
|
||||
tableModel.resync();
|
||||
}
|
||||
|
||||
void deleteSelected() {
|
||||
int[] selected = listsTable.getSelectedRows();
|
||||
if (selected.length == 0) {
|
||||
return;
|
||||
}
|
||||
tableModel.deleteSelected(selected);
|
||||
}
|
||||
|
||||
private class KeywordListTableModel extends AbstractTableModel {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@ -586,8 +598,8 @@ class GlobalListsManagementPanel extends javax.swing.JPanel implements OptionsPa
|
||||
//delete selected from handle, events are fired from the handle
|
||||
void deleteSelected(int[] selected) {
|
||||
List<String> toDel = new ArrayList<>();
|
||||
for (int i = 0; i < selected.length; i++) {
|
||||
toDel.add((String) getValueAt(0, selected[i]));
|
||||
for (int i : selected) {
|
||||
toDel.add(getValueAt(i, 0).toString());
|
||||
}
|
||||
for (String del : toDel) {
|
||||
listsHandle.deleteList(del);
|
||||
|
@ -216,6 +216,14 @@ class TestRunner(object):
|
||||
TestRunner._run_ant(test_data)
|
||||
time.sleep(2) # Give everything a second to process
|
||||
|
||||
# exit if any build errors are found in antlog.txt
|
||||
antlog = 'antlog.txt'
|
||||
logs_path = test_data.logs_dir
|
||||
for ant_line in codecs.open(os.path.join(logs_path, os.pardir, antlog)):
|
||||
ant_ignoreCase = ant_line.lower()
|
||||
if ant_line.startswith("BUILD FAILED") or "fatal error" in ant_ignoreCase or "crashed" in ant_ignoreCase:
|
||||
Errors.print_error("Autopsy test failed. Please check the build log antlog.txt for details.")
|
||||
sys.exit(1)
|
||||
# exit if .db was not created
|
||||
if not file_exists(test_data.get_db_path(DBType.OUTPUT)):
|
||||
Errors.print_error("Autopsy did not run properly; No .db file was created")
|
||||
|
Loading…
x
Reference in New Issue
Block a user