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:
Raman 2017-07-31 12:35:26 -04:00
commit 4fdea244af
23 changed files with 576 additions and 338 deletions

View File

@ -861,7 +861,7 @@ public class EamDbSettingsDialog extends JDialog {
* *
* @return true * @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."}) "EamDbSettingsDialog.validation.failedConnection=The connection to the database failed. Update the settings and try the Test again."})
private boolean enableTestButton(boolean isValidInput) { private boolean enableTestButton(boolean isValidInput) {
if (selectedPlatform != EamDbPlatformEnum.DISABLED && isValidInput) { if (selectedPlatform != EamDbPlatformEnum.DISABLED && isValidInput) {

View File

@ -220,6 +220,7 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer {
@Override @Override
public void resetComponent() { public void resetComponent() {
setText("");
return; return;
} }

View File

@ -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 final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private String[][] rowData = null; private String[][] rowData = null;
private final String artifactDisplayName; private final String artifactDisplayName;
private final Content content;
ResultsTableArtifact(BlackboardArtifact artifact) { ResultsTableArtifact(BlackboardArtifact artifact, Content content) {
artifactDisplayName = artifact.getDisplayName(); artifactDisplayName = artifact.getDisplayName();
this.content = content;
addRows(artifact); addRows(artifact);
} }
ResultsTableArtifact(String errorMsg) { ResultsTableArtifact(String errorMsg) {
artifactDisplayName = errorMsg; artifactDisplayName = errorMsg;
rowData = new String[1][3]; rowData = new String[1][3];
rowData[0] = new String[]{"", errorMsg, ""}; rowData[0] = new String[]{"", errorMsg, ""};
content = null;
} }
private String[][] getRows() { private String[][] getRows() {
@ -514,7 +515,6 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
private void addRows(BlackboardArtifact artifact) { private void addRows(BlackboardArtifact artifact) {
List<String[]> rowsToAdd = new ArrayList<>(); List<String[]> rowsToAdd = new ArrayList<>();
try { try {
Content content = artifact.getSleuthkitCase().getContentById(artifact.getObjectID());
/* /*
* Add rows for each attribute. * Add rows for each attribute.
*/ */
@ -701,12 +701,15 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
if (contents.isEmpty()) { if (contents.isEmpty()) {
return new ViewUpdate(getArtifactContents().size(), currentPage, ERROR_TEXT); return new ViewUpdate(getArtifactContents().size(), currentPage, ERROR_TEXT);
} }
Content underlyingContent = null;
for (Content content : contents) { for (Content content : contents) {
if ( (content != null) && (!(content instanceof BlackboardArtifact)) ) { if ( (content != null) && (!(content instanceof BlackboardArtifact)) ) {
// Get all of the blackboard artifacts associated with the content. These are what this // Get all of the blackboard artifacts associated with the content. These are what this
// viewer displays. // viewer displays.
try { try {
artifacts = content.getAllArtifacts(); artifacts = content.getAllArtifacts();
underlyingContent = content;
break;
} catch (TskException ex) { } catch (TskException ex) {
logger.log(Level.SEVERE, "Couldn't get artifacts", ex); //NON-NLS logger.log(Level.SEVERE, "Couldn't get artifacts", ex); //NON-NLS
return new ViewUpdate(getArtifactContents().size(), currentPage, ERROR_TEXT); 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. // Build the new artifact contents cache.
ArrayList<ResultsTableArtifact> artifactContents = new ArrayList<>(); ArrayList<ResultsTableArtifact> artifactContents = new ArrayList<>();
for (BlackboardArtifact artifact : artifacts) { 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, // If the node has an underlying blackboard artifact, show it. If not,

View File

@ -28,6 +28,7 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException; import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService; 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). * children nodes (which might not be preloaded at this point).
*/ */
// get list of supported children sorted by persisted criteria // get list of supported children sorted by persisted criteria
final List<Node> suppContent = final List<Node> suppContent
Stream.of(parent.getChildren().getNodes()) = Stream.of(parent.getChildren().getNodes())
.filter(ThumbnailViewChildren::isSupported) .filter(ThumbnailViewChildren::isSupported)
.sorted(getComparator()) .sorted(getComparator())
.collect(Collectors.toList()); .collect(Collectors.toList());
if (suppContent.isEmpty()) { if (suppContent.isEmpty()) {
//if there are no images, there is nothing more to do //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; private boolean cancelled = false;
ThumbnailLoadTask() { 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()); progressText = Bundle.ThumbnailViewNode_progressHandle_text(content.getName());
progressHandle = ProgressHandleFactory.createSystemHandle(progressText); progressHandle = ProgressHandleFactory.createSystemHandle(progressText);

View File

@ -18,6 +18,8 @@
*/ */
package org.sleuthkit.autopsy.datamodel; package org.sleuthkit.autopsy.datamodel;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.text.MessageFormat; import java.text.MessageFormat;
@ -26,6 +28,8 @@ import java.util.Arrays;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.swing.Action; import javax.swing.Action;
@ -35,12 +39,12 @@ import org.openide.util.Lookup;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups; import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case; 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.BlackBoardArtifactTagAddedEvent;
import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagDeletedEvent; import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagDeletedEvent;
import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent;
import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent; 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 static org.sleuthkit.autopsy.datamodel.DisplayableItemNode.findLinked;
import org.sleuthkit.autopsy.timeline.actions.ViewArtifactInTimelineAction; import org.sleuthkit.autopsy.timeline.actions.ViewArtifactInTimelineAction;
import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction; import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction;
@ -59,10 +63,15 @@ import org.sleuthkit.datamodel.TskCoreException;
*/ */
public class BlackboardArtifactNode extends DisplayableItemNode { 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 final BlackboardArtifact artifact;
private Content associated = null; private Content associated = null;
private List<NodeProperty<? extends Object>> customProperties; 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 * Artifact types which should have the full unique path of the associated
* content as a property. * content as a property.
@ -107,6 +116,7 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
if (evt.getNewValue() == null) { if (evt.getNewValue() == null) {
// case was closed. Remove listeners so that we don't get called with a stale case handle // case was closed. Remove listeners so that we don't get called with a stale case handle
removeListeners(); removeListeners();
contentCache.invalidateAll();
} }
} }
} }
@ -493,43 +503,43 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
} }
/** /**
* Fill map with EmailMsg properties, not all attributes are filled * Fill map with EmailMsg properties, not all attributes are filled
* *
* @param map map with preserved ordering, where property names/values * @param map map with preserved ordering, where property names/values
* are put * are put
* @param attribute attribute to check/fill as property * @param attribute attribute to check/fill as property
*/ */
private void addEmailMsgProperty(Map<String, Object> map, BlackboardAttribute attribute ) { private void addEmailMsgProperty(Map<String, Object> map, BlackboardAttribute attribute ) {
final int attributeTypeID = attribute.getAttributeType().getTypeID(); final int attributeTypeID = attribute.getAttributeType().getTypeID();
// Skip certain Email msg attributes // Skip certain Email msg attributes
if (attributeTypeID == ATTRIBUTE_TYPE.TSK_DATETIME_SENT.getTypeID() if (attributeTypeID == ATTRIBUTE_TYPE.TSK_DATETIME_SENT.getTypeID()
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML.getTypeID() || attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML.getTypeID()
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF.getTypeID() || attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF.getTypeID()
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_BCC.getTypeID() || attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_BCC.getTypeID()
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CC.getTypeID() || attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CC.getTypeID()
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_HEADERS.getTypeID() || attributeTypeID == ATTRIBUTE_TYPE.TSK_HEADERS.getTypeID()
) { ) {
// do nothing // do nothing
} }
else if (attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_PLAIN.getTypeID()) { else if (attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_PLAIN.getTypeID()) {
String value = attribute.getDisplayString(); String value = attribute.getDisplayString();
if (value.length() > 160) { if (value.length() > 160) {
value = value.substring(0, 160) + "..."; value = value.substring(0, 160) + "...";
} }
map.put(attribute.getAttributeType().getDisplayName(), value); map.put(attribute.getAttributeType().getDisplayName(), value);
} }
else if (attribute.getAttributeType().getValueType() == BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME) { 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 { else {
map.put(attribute.getAttributeType().getDisplayName(), attribute.getDisplayString()); map.put(attribute.getAttributeType().getDisplayName(), attribute.getDisplayString());
} }
} }
@Override @Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) { public <T> T accept(DisplayableItemNodeVisitor<T> v) {
@ -539,31 +549,25 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
/** /**
* Create a Lookup based on what is in the passed in artifact. * 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) { private static Lookup createLookup(BlackboardArtifact artifact) {
List<Object> forLookup = new ArrayList<>();
forLookup.add(artifact);
// Add the content the artifact is associated with // Add the content the artifact is associated with
Content content = getAssociatedContent(artifact); final long objectID = artifact.getObjectID();
if (content != null) {
forLookup.add(content);
}
return Lookups.fixed(forLookup.toArray(new Object[forLookup.size()]));
}
private static Content getAssociatedContent(BlackboardArtifact artifact) {
try { try {
return artifact.getSleuthkitCase().getContentById(artifact.getObjectID()); Content content = contentCache.get(objectID, () -> artifact.getSleuthkitCase().getContentById(objectID));
} catch (TskCoreException ex) { if (content == null) {
LOGGER.log(Level.WARNING, "Getting file failed", ex); //NON-NLS 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 @Override

View File

@ -42,7 +42,6 @@ BlackboardArtifactNode.createSheet.filePath.name=File Path
BlackboardArtifactNode.createSheet.filePath.displayName=File Path BlackboardArtifactNode.createSheet.filePath.displayName=File Path
BlackboardArtifactNode.createSheet.dataSrc.name=Data Source BlackboardArtifactNode.createSheet.dataSrc.name=Data Source
BlackboardArtifactNode.createSheet.dataSrc.displayName=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.srcFile.text=Source File
BlackboardArtifactTagNode.createSheet.unavail.text=Unavailable BlackboardArtifactTagNode.createSheet.unavail.text=Unavailable
BlackboardArtifactTagNode.createSheet.srcFilePath.text=Source File Path BlackboardArtifactTagNode.createSheet.srcFilePath.text=Source File Path
@ -87,8 +86,8 @@ DeletedContent.deletedContentsNode.name=Deleted Files
DeletedContent.createSheet.name.name=Name DeletedContent.createSheet.name.name=Name
DeletedContent.createSheet.name.displayName=Name DeletedContent.createSheet.name.displayName=Name
DeletedContent.createSheet.name.desc=no description DeletedContent.createSheet.name.desc=no description
DeletedContent.createSheet.filterType.name=Filter Type DeletedContent.createSheet.filterType.name=Type
DeletedContent.createSheet.filterType.displayName=Filter Type DeletedContent.createSheet.filterType.displayName=Type
DeletedContent.createSheet.filterType.desc=no description 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.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} 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.name=Name
FileSize.createSheet.name.displayName=Name FileSize.createSheet.name.displayName=Name
FileSize.createSheet.name.desc=no description FileSize.createSheet.name.desc=no description
FileSize.createSheet.filterType.name=Filter Type FileSize.createSheet.filterType.name=Size Range
FileSize.createSheet.filterType.displayName=Filter Type FileSize.createSheet.filterType.displayName=Size Range
FileSize.createSheet.filterType.desc=no description FileSize.createSheet.filterType.desc=no description
FileSize.exception.notSupported.msg=Not supported for this type of Displayable Item\: {0} 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} FileTypeChildren.exception.notSupported.msg=Not supported for this type of Displayable Item\: {0}
FileTypesByExtNode.createSheet.filterType.name=Filter Type FileTypesByExtNode.createSheet.filterType.name=File Type
FileTypesByExtNode.createSheet.filterType.displayName=Filter Type FileTypesByExtNode.createSheet.filterType.displayName=File Type
FileTypesByExtNode.createSheet.filterType.desc=no description FileTypesByExtNode.createSheet.filterType.desc=no description
FileTypesByExtNode.createSheet.fileExt.name=File Extensions FileTypesByExtNode.createSheet.fileExt.name=File Extensions
FileTypesByExtNode.createSheet.fileExt.displayName=File Extensions FileTypesByExtNode.createSheet.fileExt.displayName=File Extensions

View File

@ -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.filePath.displayName=\u30d5\u30a1\u30a4\u30eb\u30d1\u30b9
BlackboardArtifactNode.createSheet.dataSrc.name=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9 BlackboardArtifactNode.createSheet.dataSrc.name=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9
BlackboardArtifactNode.createSheet.dataSrc.displayName=\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.srcFile.text=\u30bd\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb
BlackboardArtifactTagNode.createSheet.unavail.text=\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093 BlackboardArtifactTagNode.createSheet.unavail.text=\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093
BlackboardArtifactTagNode.createSheet.srcFilePath.text=\u30bd\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb\u30d1\u30b9 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.fsDelFilter.text=\u30d5\u30a1\u30a4\u30eb\u30b7\u30b9\u30c6\u30e0
DeletedContent.allDelFilter.text=\u3059\u3079\u3066 DeletedContent.allDelFilter.text=\u3059\u3079\u3066
DeletedContent.deletedContentsNode.name=\u524a\u9664\u3055\u308c\u305f\u30d5\u30a1\u30a4\u30eb 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.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.name=\u30d5\u30a3\u30eb\u30bf\u30fc\u30bf\u30a4\u30d7
DeletedContent.createSheet.filterType.displayName=\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.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 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.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.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.name=\u30d5\u30a3\u30eb\u30bf\u30fc\u30bf\u30a4\u30d7
FileSize.createSheet.filterType.displayName=\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.autoDocPdfFilter.text=PDF
FileTypeExtensionFilters.autDocTxtFilter.text=\u30d7\u30ec\u30fc\u30f3\u30c6\u30ad\u30b9\u30c8 FileTypeExtensionFilters.autDocTxtFilter.text=\u30d7\u30ec\u30fc\u30f3\u30c6\u30ad\u30b9\u30c8
FileTypeExtensionFilters.autDocRtfFilter.text=\u30ea\u30c3\u30c1\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.filterType.desc=\u8aac\u660e\u304c\u3042\u308a\u307e\u305b\u3093
FileTypesByExtNode.createSheet.fileExt.name=\u30d5\u30a1\u30a4\u30eb\u62e1\u5f35\u5b50 FileTypesByExtNode.createSheet.fileExt.name=\u30d5\u30a1\u30a4\u30eb\u62e1\u5f35\u5b50
FileTypesByExtNode.createSheet.fileExt.displayName=\u30d5\u30a1\u30a4\u30eb\u62e1\u5f35\u5b50 FileTypesByExtNode.createSheet.fileExt.displayName=\u30d5\u30a1\u30a4\u30eb\u62e1\u5f35\u5b50

View File

@ -30,7 +30,6 @@ import org.openide.util.Utilities;
import org.sleuthkit.autopsy.actions.AddContentTagAction; import org.sleuthkit.autopsy.actions.AddContentTagAction;
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction; import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.coreutils.ImageUtils;
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.HashSearchAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction;
@ -62,8 +61,7 @@ public class FileNode extends AbstractFsContentNode<AbstractFile> {
} else { } else {
ext = "." + ext; ext = "." + ext;
} }
if (ImageUtils.isImageThumbnailSupported(file) if (FileTypeExtensions.getImageExtensions().contains(ext)) {
|| FileTypeExtensions.getImageExtensions().contains(ext)) {
return "org/sleuthkit/autopsy/images/image-file.png"; //NON-NLS return "org/sleuthkit/autopsy/images/image-file.png"; //NON-NLS
} }
if (FileTypeExtensions.getVideoExtensions().contains(ext)) { if (FileTypeExtensions.getVideoExtensions().contains(ext)) {

View File

@ -45,6 +45,7 @@ import org.sleuthkit.datamodel.File;
import org.sleuthkit.datamodel.FsContent; import org.sleuthkit.datamodel.FsContent;
import org.sleuthkit.datamodel.LayoutFile; import org.sleuthkit.datamodel.LayoutFile;
import org.sleuthkit.datamodel.LocalFile; import org.sleuthkit.datamodel.LocalFile;
import org.sleuthkit.datamodel.SlackFile;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
@ -483,6 +484,11 @@ public class FileSize implements AutopsyVisitableItem {
return new FileNode(f, false); return new FileNode(f, false);
} }
@Override
public FileNode visit(SlackFile f) {
return new FileNode(f, false);
}
@Override @Override
protected AbstractNode defaultVisit(Content di) { protected AbstractNode defaultVisit(Content di) {
throw new UnsupportedOperationException( throw new UnsupportedOperationException(

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2016 Basis Technology Corp. * Copyright 2011-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -18,9 +18,12 @@
*/ */
package org.sleuthkit.autopsy.datamodel; package org.sleuthkit.autopsy.datamodel;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import java.util.Observable; import java.util.Observable;
import java.util.Observer; import java.util.Observer;
import java.util.Set;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.logging.Level; import java.util.logging.Level;
import javax.swing.SwingWorker; import javax.swing.SwingWorker;
@ -31,6 +34,8 @@ import org.openide.util.Lookup;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups; import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.coreutils.Logger; 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.Content;
import org.sleuthkit.datamodel.ContentVisitor; import org.sleuthkit.datamodel.ContentVisitor;
import org.sleuthkit.datamodel.DerivedFile; import org.sleuthkit.datamodel.DerivedFile;
@ -40,6 +45,7 @@ import org.sleuthkit.datamodel.LayoutFile;
import org.sleuthkit.datamodel.LocalFile; import org.sleuthkit.datamodel.LocalFile;
import org.sleuthkit.datamodel.SlackFile; import org.sleuthkit.datamodel.SlackFile;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.SleuthkitItemVisitor;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
/** /**
@ -47,10 +53,24 @@ import org.sleuthkit.datamodel.TskCoreException;
*/ */
public final class FileTypes implements AutopsyVisitableItem { 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 final SleuthkitCase skCase;
private boolean showCounts = true;
FileTypes(SleuthkitCase skCase) { FileTypes(SleuthkitCase skCase) {
this.skCase = skCase; this.skCase = skCase;
@ -66,15 +86,16 @@ public final class FileTypes implements AutopsyVisitableItem {
} }
/** /**
* Should the nodes show counts? * Check the db to determine if the nodes should show child counts.
*
*
* @return True, unless the DB has more than 200k rows.
*/ */
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) { if (showCounts) {
try { try {
if (skCase.countFilesWhere("1=1") > 200000) { //NON-NLS if (skCase.countFilesWhere("1=1") > NODE_COUNT_FILE_TABLE_THRESHOLD) { //NON-NLS
showCounts = false; showCounts = false;
} }
} catch (TskCoreException tskCoreException) { } catch (TskCoreException tskCoreException) {
@ -82,10 +103,7 @@ public final class FileTypes implements AutopsyVisitableItem {
logger.log(Level.SEVERE, "Error counting files.", tskCoreException); //NON-NLS 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. * 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 FileTypesByExtension(FileTypes.this),
new FileTypesByMimeType(FileTypes.this))), new FileTypesByMimeType(FileTypes.this))),
Lookups.singleton(NAME)); Lookups.singleton(NAME));
setName(NAME); this.setName(NAME);
setDisplayName(NAME); this.setDisplayName(NAME);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png"); //NON-NLS 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 * Updates the display name of the mediaSubTypeNode to include the count
* of files which it represents. * of files which it represents.
*/ */
@NbBundle.Messages("FileTypes.bgCounting.placeholder=(counting...)") @NbBundle.Messages("FileTypes.bgCounting.placeholder= (counting...)")
void updateDisplayName() { void updateDisplayName() {
if (typesRoot.shouldShowCounts()) { if (typesRoot.showCounts) {
//only show "(counting...)" the first time, otherwise it is distracting. //only show "(counting...)" the first time, otherwise it is distracting.
setDisplayName(getDisplayNameBase() + ((childCount < 0) ? Bundle.FileTypes_bgCounting_placeholder() setDisplayName(getDisplayNameBase() + ((childCount < 0) ? Bundle.FileTypes_bgCounting_placeholder()
: ("(" + childCount + ")"))); //NON-NLS : ("(" + childCount + ")"))); //NON-NLS
@ -239,8 +257,186 @@ public final class FileTypes implements AutopsyVisitableItem {
} }
}.execute(); }.execute();
} else { } 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();
}
}
} }

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-17 Basis Technology Corp. * Copyright 2011-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * 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.List;
import java.util.Observable; import java.util.Observable;
import java.util.Observer; import java.util.Observer;
import java.util.function.Function;
import java.util.logging.Level; 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.ChildFactory;
import org.openide.nodes.Children; import org.openide.nodes.Children;
import org.openide.nodes.Node; 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.casemodule.Case;
import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesKey;
import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
@ -87,7 +92,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
*/ */
try { try {
Case.getCurrentCase(); Case.getCurrentCase();
typesRoot.shouldShowCounts(); typesRoot.updateShowCounts();
update(); update();
} catch (IllegalStateException notUsed) { } catch (IllegalStateException notUsed) {
/** /**
@ -147,8 +152,9 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
* provides updates on events * provides updates on events
*/ */
private FileTypesByExtNode(SleuthkitCase skCase, FileTypesByExtension.RootFilter filter, FileTypesByExtObservable o) { private FileTypesByExtNode(SleuthkitCase skCase, FileTypesByExtension.RootFilter filter, FileTypesByExtObservable o) {
super(Children.create(new FileTypesByExtNodeChildren(skCase, filter, o), true), 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; this.filter = filter;
// root node of tree // root node of tree
@ -157,7 +163,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
super.setDisplayName(FNAME); super.setDisplayName(FNAME);
} // sub-node in file tree (i.e. documents, exec, etc.) } // sub-node in file tree (i.e. documents, exec, etc.)
else { else {
super.setName(filter.getName()); super.setName(filter.getDisplayName());
super.setDisplayName(filter.getDisplayName()); super.setDisplayName(filter.getDisplayName());
} }
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png"); //NON-NLS this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png"); //NON-NLS
@ -181,7 +187,16 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
ss = Sheet.createPropertiesSet(); ss = Sheet.createPropertiesSet();
s.put(ss); 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; return s;
} }
@ -272,7 +287,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
super(typesRoot, Children.create(new FileExtensionNodeChildren(filter, skCase, o), true), super(typesRoot, Children.create(new FileExtensionNodeChildren(filter, skCase, o), true),
Lookups.singleton(filter.getDisplayName())); Lookups.singleton(filter.getDisplayName()));
this.filter = filter; this.filter = filter;
setName(filter.getName()); super.setName(filter.getDisplayName());
updateDisplayName(); updateDisplayName();
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-filter-icon.png"); //NON-NLS 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) { private String createQuery(FileTypesByExtension.SearchFilterInterface filter) {
StringBuilder query = new StringBuilder(); if (filter.getFilter().isEmpty()) {
query.append("(dir_type = ").append(TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue()).append(")"); //NON-NLS // We should never be given a search filter without extensions
if (UserPreferences.hideKnownFilesInViewsTree()) { // but if we are it is clearly a programming error so we throw
query.append(" AND (known IS NULL OR known != ").append(TskData.FileKnown.KNOWN.getFileKnownValue()).append(")"); //NON-NLS // an IllegalArgumentException.
throw new IllegalArgumentException("Empty filter list passed to createQuery()"); // NON-NLS
} }
query.append(" AND (NULL"); //NON-NLS
for (String s : filter.getFilter()) { String query = "(dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + ")"
query.append(" OR LOWER(name) LIKE LOWER('%").append(s).append("')"); //NON-NLS + (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. * 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 SleuthkitCase skCase;
private final FileTypesByExtension.SearchFilterInterface filter; private final FileTypesByExtension.SearchFilterInterface filter;
@ -387,9 +421,10 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
} }
@Override @Override
protected boolean createKeys(List<Content> list) { protected boolean createKeys(List<FileTypesKey> list) {
try { 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) { } 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
} }
@ -397,7 +432,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
} }
@Override @Override
protected Node createNodeForKey(Content key) { protected Node createNodeForKey(FileTypesKey key) {
return key.accept(new FileTypes.FileNodeCreationVisitor()); return key.accept(new FileTypes.FileNodeCreationVisitor());
} }
} }
@ -419,10 +454,10 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
FileTypeExtensions.getArchiveExtensions()), FileTypeExtensions.getArchiveExtensions()),
TSK_DOCUMENT_FILTER(3, "TSK_DOCUMENT_FILTER", //NON-NLS TSK_DOCUMENT_FILTER(3, "TSK_DOCUMENT_FILTER", //NON-NLS
NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskDocumentFilter.text"), 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 TSK_EXECUTABLE_FILTER(3, "TSK_EXECUTABLE_FILTER", //NON-NLS
NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskExecFilter.text"), 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 int id;
private final String name; private final String name;

View File

@ -30,16 +30,20 @@ import java.util.Map;
import java.util.Observable; import java.util.Observable;
import java.util.Observer; import java.util.Observer;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.openide.nodes.ChildFactory; import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children; import org.openide.nodes.Children;
import org.openide.nodes.Node; import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case; 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.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesKey;
import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
@ -55,6 +59,7 @@ import org.sleuthkit.datamodel.TskData;
public final class FileTypesByMimeType extends Observable implements AutopsyVisitableItem { public final class FileTypesByMimeType extends Observable implements AutopsyVisitableItem {
private final static Logger logger = Logger.getLogger(FileTypesByMimeType.class.getName()); private final static Logger logger = Logger.getLogger(FileTypesByMimeType.class.getName());
private final SleuthkitCase skCase; private final SleuthkitCase skCase;
/** /**
* The nodes of this tree will be determined dynamically by the mimetypes * 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. * 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 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 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 * The pcl is in the class because it has the easiest mechanisms to add and
* remove itself during its life cycles. * remove itself during its life cycles.
*/ */
private final PropertyChangeListener pcl; private final PropertyChangeListener pcl;
/** /**
* Performs the query on the database to get all distinct MIME types of * Create the base expression used as the where clause in the queries for
* files in it, and populate the hashmap with those results. * 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() { static private String createBaseWhereExpr() {
String query = "SELECT mime_type,count(*) as count from tsk_files " return "(dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + ")"
+ " where mime_type IS NOT null "
+ " AND dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue()
+ " AND (type IN (" + " AND (type IN ("
+ TskData.TSK_DB_FILES_TYPE_ENUM.FS.ordinal() + "," + TskData.TSK_DB_FILES_TYPE_ENUM.FS.ordinal() + ","
+ TskData.TSK_DB_FILES_TYPE_ENUM.CARVED.ordinal() + "," + TskData.TSK_DB_FILES_TYPE_ENUM.CARVED.ordinal() + ","
+ TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.ordinal() + "," + TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.ordinal() + ","
+ TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal() + TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal()
+ ((UserPreferences.hideSlackFilesInViewsTree()) ? "" + (hideSlackFilesInViewsTree() ? "" : ("," + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal()))
: ("," + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal())) + "))"
+ "))" + " GROUP BY mime_type"; + (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) { synchronized (existingMimeTypeCounts) {
existingMimeTypeCounts.clear(); existingMimeTypeCounts.clear();
@ -114,7 +136,7 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
} }
} }
} catch (TskCoreException | SQLException ex) { } 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 { try {
Case.getCurrentCase(); Case.getCurrentCase();
typesRoot.shouldShowCounts(); typesRoot.updateShowCounts();
populateHashMap(); populateHashMap();
} catch (IllegalStateException notUsed) { } catch (IllegalStateException notUsed) {
/** /**
@ -187,11 +209,12 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
*/ */
class ByMimeTypeNode extends DisplayableItemNode { 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(); final String NAME = Bundle.FileTypesByMimeType_name_text();
ByMimeTypeNode() { ByMimeTypeNode() {
super(Children.create(new ByMimeTypeNodeChildren(), true)); super(Children.create(new ByMimeTypeNodeChildren(), true), Lookups.singleton(Bundle.FileTypesByMimeType_name_text()));
super.setName(NAME); super.setName(NAME);
super.setDisplayName(NAME); super.setDisplayName(NAME);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png"); 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 { 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) { MediaTypeNode(String name) {
super(Children.create(new MediaTypeNodeChildren(name), true)); super(Children.create(new MediaTypeNodeChildren(name), true), Lookups.singleton(name));
setName(name); setName(name);
setDisplayName(name); setDisplayName(name);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png"); 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); 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 @Override
public String getItemType() { public String getItemType() {
return getClass().getName(); 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 { 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 mimeType;
private final String subType; private final String subType;
private MediaSubTypeNode(String mimeType) { 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.mimeType = mimeType;
this.subType = StringUtils.substringAfter(mimeType, "/"); this.subType = StringUtils.substringAfter(mimeType, "/");
super.setName(mimeType); super.setName(mimeType);
super.setDisplayName(subType);
updateDisplayName(); updateDisplayName();
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-filter-icon.png"); //NON-NLS this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-filter-icon.png"); //NON-NLS
addObserver(this); addObserver(this);
} }
@ -347,6 +392,17 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
public <T> T accept(DisplayableItemNodeVisitor< T> v) { public <T> T accept(DisplayableItemNodeVisitor< T> v) {
return v.visit(this); 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 @Override
public String getItemType() { 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 * 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 * files that match MimeType which is represented by this position in the
* tree. * tree.
*/ */
private class MediaSubTypeNodeChildren extends ChildFactory.Detachable<Content> implements Observer { private class MediaSubTypeNodeChildren extends ChildFactory.Detachable<FileTypesKey> implements Observer {
private final String mimeType; private final String mimeType;
@ -411,23 +440,13 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
this.mimeType = mimeType; 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 @Override
protected boolean createKeys(List<Content> list) { protected boolean createKeys(List<FileTypesKey> list) {
try { try {
List<AbstractFile> files = skCase.findAllFilesWhere(createQuery(mimeType)); list.addAll(skCase.findAllFilesWhere(createBaseWhereExpr() + " AND mime_type = '" + mimeType + "'")
list.addAll(files); .stream().map(f -> new FileTypesKey(f)).collect(Collectors.toList())); //NON-NLS
} catch (TskCoreException ex) { } 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; return true;
} }
@ -437,19 +456,9 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
refresh(true); refresh(true);
} }
/**
* Creates the content to populate the Directory Listing Table view for
* each file
*
* @param key
*
* @return
*/
@Override @Override
protected Node createNodeForKey(Content key) { protected Node createNodeForKey(FileTypesKey key) {
return key.accept(new FileTypes.FileNodeCreationVisitor()); return key.accept(new FileTypes.FileNodeCreationVisitor());
} }
} }
} }

View File

@ -24,7 +24,6 @@ import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
@ -33,6 +32,7 @@ import java.util.Observable;
import java.util.Observer; import java.util.Observer;
import java.util.Set; import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.openide.nodes.ChildFactory; import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children; 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 + " OR attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID()//NON-NLS
+ ")"; //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) { public KeywordHits(SleuthkitCase skCase) {
this.skCase = skCase; this.skCase = skCase;
keywordResults = new KeywordResults(); keywordResults = new KeywordResults();
@ -265,7 +269,6 @@ public class KeywordHits implements AutopsyVisitableItem {
addRegExpToList(listMap, reg, word, id); addRegExpToList(listMap, reg, word, id);
} }
} else {//single term } else {//single term
if ("1".equals(kwType) || reg == null) { //literal, substring or exact if ("1".equals(kwType) || reg == null) { //literal, substring or exact
/* /*
* Substring, treated same as exact match. "1" is * Substring, treated same as exact match. "1" is
@ -626,9 +629,8 @@ public class KeywordHits implements AutopsyVisitableItem {
@Override @Override
public boolean isLeafTypeNode() { public boolean isLeafTypeNode() {
List<String> instances = keywordResults.getKeywordInstances(setName, keyword);
// is this an exact/substring match (i.e. did we use the DEFAULT name)? // 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 @Override
@ -661,7 +663,6 @@ public class KeywordHits implements AutopsyVisitableItem {
return s; return s;
} }
} }
/** /**
@ -706,7 +707,6 @@ public class KeywordHits implements AutopsyVisitableItem {
private final String keyword; private final String keyword;
private final String setName; private final String setName;
private final Map<RegExpInstanceKey, DisplayableItemNode> nodesMap = new HashMap<>();
private RegExpInstancesFactory(String setName, String keyword) { private RegExpInstancesFactory(String setName, String keyword) {
super(); super();
@ -720,29 +720,20 @@ public class KeywordHits implements AutopsyVisitableItem {
// The keys are different depending on what we are displaying. // The keys are different depending on what we are displaying.
// regexp get another layer to show instances. // regexp get another layer to show instances.
// Exact/substring matches don't. // Exact/substring matches don't.
if ((instances.size() == 1) && (instances.get(0).equals(DEFAULT_INSTANCE_NAME))) { if (isOnlyDefaultInstance(instances)) {
for (Long id : keywordResults.getArtifactIds(setName, keyword, DEFAULT_INSTANCE_NAME)) { list.addAll(keywordResults.getArtifactIds(setName, keyword, DEFAULT_INSTANCE_NAME).stream()
RegExpInstanceKey key = new RegExpInstanceKey(id); .map(RegExpInstanceKey::new)
nodesMap.computeIfAbsent(key, k -> createNode(k)); .collect(Collectors.toList()));
list.add(key);
}
} else { } else {
for (String instance : instances) { list.addAll(instances.stream()
RegExpInstanceKey key = new RegExpInstanceKey(instance); .map(RegExpInstanceKey::new)
nodesMap.computeIfAbsent(key, k -> createNode(k)); .collect(Collectors.toList()));
list.add(key);
}
} }
return true; return true;
} }
@Override @Override
protected Node createNodeForKey(RegExpInstanceKey key) { protected Node createNodeForKey(RegExpInstanceKey key) {
return nodesMap.get(key);
}
private DisplayableItemNode createNode(RegExpInstanceKey key) {
if (key.isRegExp()) { if (key.isRegExp()) {
return new RegExpInstanceNode(setName, keyword, key.getRegExpKey()); return new RegExpInstanceNode(setName, keyword, key.getRegExpKey());
} else { } else {
@ -750,6 +741,7 @@ public class KeywordHits implements AutopsyVisitableItem {
return createBlackboardArtifactNode(key.getIdKey()); return createBlackboardArtifactNode(key.getIdKey());
} }
} }
} }
/** /**
@ -884,7 +876,6 @@ public class KeywordHits implements AutopsyVisitableItem {
private final String keyword; private final String keyword;
private final String setName; private final String setName;
private final String instance; private final String instance;
private final Map<Long, BlackboardArtifactNode> nodesMap = new HashMap<>();
private HitsFactory(String setName, String keyword, String instance) { private HitsFactory(String setName, String keyword, String instance) {
super(); super();
@ -895,16 +886,13 @@ public class KeywordHits implements AutopsyVisitableItem {
@Override @Override
protected boolean createKeys(List<Long> list) { protected boolean createKeys(List<Long> list) {
for (Long id : keywordResults.getArtifactIds(setName, keyword, instance)) { list.addAll(keywordResults.getArtifactIds(setName, keyword, instance));
nodesMap.computeIfAbsent(id, i -> createBlackboardArtifactNode(i));
list.add(id);
}
return true; return true;
} }
@Override @Override
protected Node createNodeForKey(Long artifactId) { protected Node createNodeForKey(Long artifactId) {
return nodesMap.get(artifactId); return createBlackboardArtifactNode(artifactId);
} }
} }
} }

View File

@ -417,7 +417,9 @@ final class ExtractUnallocAction extends AbstractAction {
try { try {
List<LayoutFile> lflst = new ArrayList<>(); List<LayoutFile> lflst = new ArrayList<>();
for (Content layout : vd.getChildren()) { for (Content layout : vd.getChildren()) {
lflst.add((LayoutFile) layout); if(layout instanceof LayoutFile){
lflst.add((LayoutFile) layout);
}
} }
return lflst; return lflst;
} catch (TskCoreException tce) { } catch (TskCoreException tce) {

View File

@ -51,6 +51,7 @@ final class GetFilesCountVisitor extends ContentVisitor.Default<Long> {
queryB.append(") )"); queryB.append(") )");
queryB.append(" AND ( (meta_type = ").append(TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); //NON-NLS 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_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(") 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(" AND (name != '.') AND (name != '..')"); //NON-NLS
queryB.append(") )"); queryB.append(") )");

View File

@ -537,10 +537,12 @@ public final class FilesSet implements Serializable {
case FILES: case FILES:
return file.isFile(); return file.isFile();
case DIRECTORIES: 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: case FILES_AND_DIRECTORIES:
return file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG 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: case ALL:
return true; //Effectively ignores the metatype condition when All is selected. return true; //Effectively ignores the metatype condition when All is selected.
default: default:

View File

@ -23,17 +23,13 @@ import java.io.FilenameFilter;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.CaseMetadata; import org.sleuthkit.autopsy.casemodule.CaseMetadata;
import org.sleuthkit.autopsy.casemodule.GeneralFilter;
final class PathUtils { final class PathUtils {
private static final List<String> CASE_METADATA_FILE_EXTS = Arrays.asList(new String[]{CaseMetadata.getFileExtension()}); private final static String CASE_METADATA_EXT = CaseMetadata.getFileExtension();
private static final GeneralFilter caseMetadataFileFilter = new GeneralFilter(CASE_METADATA_FILE_EXTS, "Autopsy Case File");
/** /**
* Searches a given folder for the most recently modified case folder for a * Searches a given folder for the most recently modified case folder for a
@ -83,34 +79,6 @@ final class PathUtils {
return caseFolderPaths; 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. * Extracts the case name from a case folder path.
* *
@ -141,6 +109,12 @@ final class PathUtils {
return Paths.get(caseFoldersPath.toString(), folderName); return Paths.get(caseFoldersPath.toString(), folderName);
} }
/**
* Supress creation of instances of this class.
*/
private PathUtils() {
}
private static class CaseFolderFilter implements FilenameFilter { private static class CaseFolderFilter implements FilenameFilter {
private final String caseName; private final String caseName;
@ -152,28 +126,37 @@ final class PathUtils {
@Override @Override
public boolean accept(File folder, String fileName) { public boolean accept(File folder, String fileName) {
File file = new File(folder, fileName); File file = new File(folder, fileName);
if (file.isDirectory() && fileName.length() > TimeStampUtils.getTimeStampLength()) { if (fileName.length() > TimeStampUtils.getTimeStampLength() && file.isDirectory()) {
Path filePath = Paths.get(file.getPath());
if (TimeStampUtils.endsWithTimeStamp(fileName)) { if (TimeStampUtils.endsWithTimeStamp(fileName)) {
if (null != caseName) { if (null != caseName) {
String fileNamePrefix = fileName.substring(0, fileName.length() - TimeStampUtils.getTimeStampLength()); String fileNamePrefix = fileName.substring(0, fileName.length() - TimeStampUtils.getTimeStampLength());
if (fileNamePrefix.equals(caseName)) { if (fileNamePrefix.equals(caseName)) {
return hasCaseMetadataFile(filePath); return hasCaseMetadataFile(file);
} }
} else { } else {
return hasCaseMetadataFile(filePath); return hasCaseMetadataFile(file);
} }
} }
} }
return false; 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() {
} }
} }

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2015 Basis Technology Corp. * Copyright 2015-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -174,6 +174,7 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel {
} }
validateSettings(); validateSettings();
enableOptionsBasedOnMode(getModeFromRadioButtons());
} }
/** /**
@ -306,10 +307,13 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel {
*/ */
boolean valid() { 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; return true;
} }
boolean isValidNodePanel = true; boolean isValidNodePanel = true;
switch (getModeFromRadioButtons()) { switch (getModeFromRadioButtons()) {
@ -326,6 +330,7 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel {
} }
break; break;
case REVIEW: case REVIEW:
jLabelInvalidImageFolder.setVisible(false);
if (!validateResultsPath()) { if (!validateResultsPath()) {
isValidNodePanel = false; isValidNodePanel = false;
} }
@ -596,23 +601,24 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel {
private void enableOptionsBasedOnMode(OptionsUiMode mode) { private void enableOptionsBasedOnMode(OptionsUiMode mode) {
if (mode != OptionsUiMode.DOWNLOADING_CONFIGURATION) { if (mode != OptionsUiMode.DOWNLOADING_CONFIGURATION) {
jRadioButtonAutomated.setEnabled(cbJoinAutoIngestCluster.isSelected()); boolean nonMasterSharedConfig = !masterNodeCheckBox.isSelected() && sharedConfigCheckbox.isSelected();
jRadioButtonReview.setEnabled(cbJoinAutoIngestCluster.isSelected()); jRadioButtonAutomated.setEnabled(cbJoinAutoIngestCluster.isSelected() && !sharedConfigCheckbox.isSelected());
jRadioButtonReview.setEnabled(cbJoinAutoIngestCluster.isSelected() && !sharedConfigCheckbox.isSelected());
jLabelSelectInputFolder.setEnabled(mode == OptionsUiMode.AIM); jLabelSelectInputFolder.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig);
inputPathTextField.setEnabled(mode == OptionsUiMode.AIM); inputPathTextField.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig);
browseInputFolderButton.setEnabled(mode == OptionsUiMode.AIM); browseInputFolderButton.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig);
jLabelSelectOutputFolder.setEnabled(mode == OptionsUiMode.AIM || mode == OptionsUiMode.REVIEW); jLabelSelectOutputFolder.setEnabled((mode == OptionsUiMode.AIM && !nonMasterSharedConfig) || mode == OptionsUiMode.REVIEW);
outputPathTextField.setEnabled(mode == OptionsUiMode.AIM || mode == OptionsUiMode.REVIEW); outputPathTextField.setEnabled((mode == OptionsUiMode.AIM && !nonMasterSharedConfig) || mode == OptionsUiMode.REVIEW);
browseOutputFolderButton.setEnabled(mode == OptionsUiMode.AIM || mode == OptionsUiMode.REVIEW); browseOutputFolderButton.setEnabled((mode == OptionsUiMode.AIM && !nonMasterSharedConfig) || mode == OptionsUiMode.REVIEW);
jPanelSharedConfig.setEnabled(mode == OptionsUiMode.AIM); jPanelSharedConfig.setEnabled(mode == OptionsUiMode.AIM);
jPanelIngestSettings.setEnabled(mode == OptionsUiMode.AIM); jPanelIngestSettings.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig);
bnEditIngestSettings.setEnabled(mode == OptionsUiMode.AIM); bnEditIngestSettings.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig);
bnAdvancedSettings.setEnabled(mode == OptionsUiMode.AIM); bnAdvancedSettings.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig);
bnLogging.setEnabled(mode == OptionsUiMode.AIM); bnLogging.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig);
jPanelSharedConfig.setEnabled(mode == OptionsUiMode.AIM); jPanelSharedConfig.setEnabled(mode == OptionsUiMode.AIM);
sharedConfigCheckbox.setEnabled(mode == OptionsUiMode.AIM); sharedConfigCheckbox.setEnabled(mode == OptionsUiMode.AIM);
masterNodeCheckBox.setEnabled(mode == OptionsUiMode.AIM && sharedConfigCheckbox.isSelected()); masterNodeCheckBox.setEnabled(mode == OptionsUiMode.AIM && sharedConfigCheckbox.isSelected());
@ -1389,12 +1395,7 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel {
void setEnabledStateForSharedConfiguration() { void setEnabledStateForSharedConfiguration() {
if (jRadioButtonAutomated.isSelected() && cbJoinAutoIngestCluster.isSelected()) { if (jRadioButtonAutomated.isSelected() && cbJoinAutoIngestCluster.isSelected()) {
if (sharedConfigCheckbox.isEnabled() && sharedConfigCheckbox.isSelected()) { enableOptionsBasedOnMode(OptionsUiMode.AIM);
setEnabledState(masterNodeCheckBox.isSelected());
} else {
// If we are in AIM mode and shared config is not enabled, allow this
setEnabledState(true);
}
} }
} }

View File

@ -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.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. AdvancedAutoIngestSettingsPanel.threadCountLabel.text=For this computer, a maximum of {0} file ingest threads should be used.
AIMIngestSettingsPanel.browseGlobalSettingsButton.text=Browse AIMIngestSettingsPanel.browseGlobalSettingsButton.text=Browse
AIMIngestSettingsPanel.globalSettingsCheckbox.text=Use shared configuration in folder:
AIMIngestSettingsPanel.globalSettingsErrorTextField.text= AIMIngestSettingsPanel.globalSettingsErrorTextField.text=
AIMIngestSettingsPanel.globalSettingsTextField.text= AIMIngestSettingsPanel.globalSettingsTextField.text=
AIMIngestSettingsPanel.jButton1.text=Download shared settings AIMIngestSettingsPanel.jButton1.text=Download shared settings
@ -33,7 +32,6 @@ AutoIngestSettingsPanel.downloadButton.text=Download Config
AutoIngestSettingsPanel.EmptySettingsDirectory=Enter path to settings directory AutoIngestSettingsPanel.EmptySettingsDirectory=Enter path to settings directory
AutoIngestSettingsPanel.ErrorSettingDefaultFolder=Error creating default folder AutoIngestSettingsPanel.ErrorSettingDefaultFolder=Error creating default folder
AutoIngestSettingsPanel.FileExportRules.text=File Export Rules AutoIngestSettingsPanel.FileExportRules.text=File Export Rules
AutoIngestSettingsPanel.globalSettingsCheckbox.text=Use shared configuration in folder:
AutoIngestSettingsPanel.globalSettingsErrorTextField.text= AutoIngestSettingsPanel.globalSettingsErrorTextField.text=
AutoIngestSettingsPanel.globalSettingsTextField.text= AutoIngestSettingsPanel.globalSettingsTextField.text=
AutoIngestSettingsPanel.ImageDirectoryUnspecified=Shared images folder must be set AutoIngestSettingsPanel.ImageDirectoryUnspecified=Shared images folder must be set

View File

@ -127,8 +127,8 @@ 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 * Adds keywords to a keyword list, returns true if at least one keyword was
* duplicates were found. * successfully added and no duplicates were found.
* *
* @return - true or false * @return - true or false
*/ */
@ -140,7 +140,7 @@ class GlobalEditListPanel extends javax.swing.JPanel implements ListSelectionLis
int dupeCount = 0; int dupeCount = 0;
int badCount = 1; // Default to 1 so we enter the loop the first time 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")); dialog.setTitle(NbBundle.getMessage(GlobalEditListPanel.class, "GlobalEditListPanel.editKeyword.title"));
} }
while (badCount > 0) { while (badCount > 0) {
@ -232,7 +232,8 @@ class GlobalEditListPanel extends javax.swing.JPanel implements ListSelectionLis
/** /**
* Remove one or more keywords from a keyword list. * 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) { private void deleteKeywordAction(int[] selectedKeywords) {
tableModel.deleteSelected(selectedKeywords); tableModel.deleteSelected(selectedKeywords);
@ -411,20 +412,15 @@ class GlobalEditListPanel extends javax.swing.JPanel implements ListSelectionLis
public void valueChanged(ListSelectionEvent e) { public void valueChanged(ListSelectionEvent e) {
//respond to list selection changes in KeywordSearchListManagementPanel //respond to list selection changes in KeywordSearchListManagementPanel
ListSelectionModel listSelectionModel = (ListSelectionModel) e.getSource(); ListSelectionModel listSelectionModel = (ListSelectionModel) e.getSource();
currentKeywordList = null;
if (!listSelectionModel.isSelectionEmpty()) { if (!listSelectionModel.isSelectionEmpty()) {
int index = listSelectionModel.getMinSelectionIndex();
listSelectionModel.setSelectionInterval(index, index);
XmlKeywordSearchList loader = XmlKeywordSearchList.getCurrent(); XmlKeywordSearchList loader = XmlKeywordSearchList.getCurrent();
if (listSelectionModel.getMinSelectionIndex() == listSelectionModel.getMaxSelectionIndex()) {
currentKeywordList = loader.getListsL(false).get(index); currentKeywordList = loader.getListsL(false).get(listSelectionModel.getMinSelectionIndex());
tableModel.resync(); }
setButtonStates();
} else {
currentKeywordList = null;
tableModel.resync();
setButtonStates();
} }
tableModel.resync();
setButtonStates();
} }
@Override @Override

View File

@ -46,8 +46,7 @@ final class GlobalListSettingsPanel extends javax.swing.JPanel implements Option
@Override @Override
public void actionPerformed(ActionEvent e) { 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)) { 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();
deleteAction(toDelete);
listsManagementPanel.resync(); listsManagementPanel.resync();
} }
} }
@ -56,9 +55,8 @@ final class GlobalListSettingsPanel extends javax.swing.JPanel implements Option
listsManagementPanel.addRenameButtonActionPerformed(new ActionListener() { listsManagementPanel.addRenameButtonActionPerformed(new ActionListener() {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
String toDelete = editListPanel.getCurrentKeywordList().getName();
if (copyAction()) { if (copyAction()) {
deleteAction(toDelete); deleteAction();
listsManagementPanel.resync(); listsManagementPanel.resync();
} }
} }
@ -83,9 +81,8 @@ final class GlobalListSettingsPanel extends javax.swing.JPanel implements Option
* *
* @param toDelete - the list to delete * @param toDelete - the list to delete
*/ */
private void deleteAction(String toDelete) { private void deleteAction() {
XmlKeywordSearchList deleter = XmlKeywordSearchList.getCurrent(); listsManagementPanel.deleteSelected();
deleter.deleteList(toDelete);
editListPanel.setCurrentKeywordList(null); editListPanel.setCurrentKeywordList(null);
editListPanel.setButtonStates(); editListPanel.setButtonStates();
listsManagementPanel.setButtonStates(); listsManagementPanel.setButtonStates();

View File

@ -102,13 +102,13 @@ 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() { private void newKeywordListAction() {
XmlKeywordSearchList writer = XmlKeywordSearchList.getCurrent(); XmlKeywordSearchList writer = XmlKeywordSearchList.getCurrent();
String listName = ""; String listName = "";
listName = (String) JOptionPane.showInputDialog(null, NbBundle.getMessage(this.getClass(), "KeywordSearch.newKwListTitle"), listName = (String) JOptionPane.showInputDialog(null, NbBundle.getMessage(this.getClass(), "KeywordSearch.newKwListTitle"),
NbBundle.getMessage(this.getClass(), "KeywordSearch.newKeywordListMsg"), JOptionPane.PLAIN_MESSAGE, null, null, listName); 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 isIngestRunning = IngestManager.getInstance().isIngestRunning();
boolean isListSelected = !listsTable.getSelectionModel().isSelectionEmpty(); boolean isListSelected = !listsTable.getSelectionModel().isSelectionEmpty();
boolean canEditList = isListSelected && !isIngestRunning; 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 // items that only need ingest to not be running
importButton.setEnabled(!isIngestRunning); 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); deleteListButton.setEnabled(canEditList);
renameListButton.setEnabled(canEditList); renameListButton.setEnabled(canEditList);
renameListButton.setEnabled(canEditList && !multiSelection);
// items that only need a selected list // items that only need a selected list
copyListButton.setEnabled(isListSelected); copyListButton.setEnabled(isListSelected);
copyListButton.setEnabled(isListSelected && !multiSelection);
exportButton.setEnabled(isListSelected); exportButton.setEnabled(isListSelected);
} }
@ -435,13 +439,9 @@ class GlobalListsManagementPanel extends javax.swing.JPanel implements OptionsPa
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_importButtonActionPerformed }//GEN-LAST:event_importButtonActionPerformed
private void listsTableKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_listsTableKeyPressed private void listsTableKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_listsTableKeyPressed
if (evt.getKeyCode() == KeyEvent.VK_DELETE) { if (evt.getKeyCode() == KeyEvent.VK_DELETE && !IngestManager.getInstance().isIngestRunning() && !listsTable.getSelectionModel().isSelectionEmpty()) {
int[] selected = listsTable.getSelectedRows(); if (KeywordSearchUtil.displayConfirmDialog(NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel1.customizeComponents.title"), NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel1.customizeComponents.body"), KeywordSearchUtil.DIALOG_MESSAGE_TYPE.WARN)) {
if (selected.length == 0) { deleteSelected();
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);
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
} else { } else {
return; return;
@ -492,7 +492,11 @@ class GlobalListsManagementPanel extends javax.swing.JPanel implements OptionsPa
XmlKeywordSearchList reader = XmlKeywordSearchList.getCurrent(); XmlKeywordSearchList reader = XmlKeywordSearchList.getCurrent();
List<KeywordList> toWrite = new ArrayList<>(); 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); final XmlKeywordSearchList exporter = new XmlKeywordSearchList(fileAbs);
boolean written = exporter.saveLists(toWrite); boolean written = exporter.saveLists(toWrite);
if (written) { if (written) {
@ -541,6 +545,14 @@ class GlobalListsManagementPanel extends javax.swing.JPanel implements OptionsPa
tableModel.resync(); tableModel.resync();
} }
void deleteSelected() {
int[] selected = listsTable.getSelectedRows();
if (selected.length == 0) {
return;
}
tableModel.deleteSelected(selected);
}
private class KeywordListTableModel extends AbstractTableModel { private class KeywordListTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L; 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 //delete selected from handle, events are fired from the handle
void deleteSelected(int[] selected) { void deleteSelected(int[] selected) {
List<String> toDel = new ArrayList<>(); List<String> toDel = new ArrayList<>();
for (int i = 0; i < selected.length; i++) { for (int i : selected) {
toDel.add((String) getValueAt(0, selected[i])); toDel.add(getValueAt(i, 0).toString());
} }
for (String del : toDel) { for (String del : toDel) {
listsHandle.deleteList(del); listsHandle.deleteList(del);

View File

@ -216,6 +216,14 @@ class TestRunner(object):
TestRunner._run_ant(test_data) TestRunner._run_ant(test_data)
time.sleep(2) # Give everything a second to process 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 # exit if .db was not created
if not file_exists(test_data.get_db_path(DBType.OUTPUT)): if not file_exists(test_data.get_db_path(DBType.OUTPUT)):
Errors.print_error("Autopsy did not run properly; No .db file was created") Errors.print_error("Autopsy did not run properly; No .db file was created")