diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java index c21596c39d..10bfbcbcee 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java @@ -111,7 +111,7 @@ abstract class AbstractContentChildren extends Keys { @Override public AbstractContentNode visit(SlackFile sf) { - return new FileNode(sf); + return new SlackFileNode(sf); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties index b4062f97d5..cec49dcdeb 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties @@ -224,6 +224,8 @@ ReportNode.reportNameProperty.desc=Name of the report ReportsListNode.displayName=Reports SlackFileFilterNode.selectionContext.dataSources=Data Sources SlackFileFilterNode.selectionContext.views=Views +SlackFileNode.getActions.viewInNewWin.text=View in New Window +SlackFileNode.getActions.viewFileInDir.text=View File in Directory TagNameNode.namePlusTags.text={0} Tags TagNameNode.contentTagTypeNodeKey.text=Content Tags TagNameNode.bbArtTagTypeNodeKey.text=Result Tags diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentNodeVisitor.java index fdda586414..6dbd8002ee 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentNodeVisitor.java @@ -41,6 +41,8 @@ interface ContentNodeVisitor { T visit(LayoutFileNode lcn); T visit(LocalFileNode dfn); + + T visit(SlackFileNode sfn); /** * Visitor with an implementable default behavior for all types. Override @@ -93,5 +95,10 @@ interface ContentNodeVisitor { public T visit(VirtualDirectoryNode ldn) { return defaultVisit(ldn); } + + @Override + public T visit(SlackFileNode sfn) { + return defaultVisit(sfn); + } } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java index cd127d5276..1b457966fe 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java @@ -43,6 +43,7 @@ import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.LayoutFile; import org.sleuthkit.datamodel.LocalFile; import org.sleuthkit.datamodel.ReadContentInputStream; +import org.sleuthkit.datamodel.SlackFile; import org.sleuthkit.datamodel.TskException; import org.sleuthkit.datamodel.VirtualDirectory; @@ -355,6 +356,18 @@ public final class ContentUtils { } return null; } + + @Override + public Void visit(SlackFile f) { + try { + ContentUtils.writeToFile(f, dest, progress, worker, source); + } catch (IOException ex) { + logger.log(Level.SEVERE, + "Trouble extracting slack file to " + dest.getAbsolutePath(), //NON-NLS + ex); + } + return null; + } @Override public Void visit(Directory dir) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java index 6f47d94093..7ab744d712 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java @@ -37,6 +37,7 @@ import org.sleuthkit.datamodel.Directory; import org.sleuthkit.datamodel.File; import org.sleuthkit.datamodel.LayoutFile; import org.sleuthkit.datamodel.LocalFile; +import org.sleuthkit.datamodel.SlackFile; import org.sleuthkit.datamodel.VirtualDirectory; /** @@ -80,6 +81,23 @@ public class DataModelActionsFactory { actions.addAll(ContextMenuExtensionPoint.getActions()); return actions; } + + public static List getActions(SlackFile slackFile, boolean isArtifactSource) { + List actions = new ArrayList<>(); + actions.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), slackFile)); + final SlackFileNode slackFileNode = new SlackFileNode(slackFile); + actions.add(null); // creates a menu separator + actions.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, slackFileNode)); + actions.add(null); // creates a menu separator + actions.add(ExtractAction.getInstance()); + actions.add(null); // creates a menu separator + actions.add(AddContentTagAction.getInstance()); + if (isArtifactSource) { + actions.add(AddBlackboardArtifactTagAction.getInstance()); + } + actions.addAll(ContextMenuExtensionPoint.getActions()); + return actions; + } public static List getActions(LayoutFile file, boolean isArtifactSource) { List actions = new ArrayList<>(); @@ -184,6 +202,8 @@ public class DataModelActionsFactory { return getActions((LocalFile) content, isArtifactSource); } else if (content instanceof DerivedFile) { return getActions((DerivedFile) content, isArtifactSource); + } else if (content instanceof SlackFile) { + return getActions((SlackFile) content, isArtifactSource); } else { return new ArrayList<>(); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java index e300ace134..a8c5714fb8 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java @@ -48,6 +48,9 @@ public interface DisplayableItemNodeVisitor { T visit(ImageNode in); T visit(VolumeNode vn); + + T visit(SlackFileNode sfn); + /* * Views Area @@ -177,6 +180,11 @@ public interface DisplayableItemNodeVisitor { return defaultVisit(vn); } + @Override + public T visit(SlackFileNode sfn) { + return defaultVisit(sfn); + } + @Override public T visit(BlackboardArtifactNode ban) { return defaultVisit(ban); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/SlackFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/SlackFileNode.java new file mode 100644 index 0000000000..eaf69a30f7 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/SlackFileNode.java @@ -0,0 +1,115 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2016 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.datamodel; + +import java.util.ArrayList; +import java.util.List; +import javax.swing.Action; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.actions.AddContentTagAction; +import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; +import org.sleuthkit.autopsy.directorytree.ExtractAction; +import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; +import org.sleuthkit.autopsy.directorytree.ViewContextAction; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM; +import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM; + +/** + * This class is the Node for an AbstractFile. It may have derived files + * children. + */ +public class SlackFileNode extends AbstractFsContentNode { + + /** + * Constructor + * + * @param file underlying Content + */ + public SlackFileNode(AbstractFile file) { + this(file, true); + + setIcon(file); + } + + public SlackFileNode(AbstractFile file, boolean directoryBrowseMode) { + super(file, directoryBrowseMode); + + setIcon(file); + } + + private void setIcon(AbstractFile file) { + // set name, display name, and icon + if (file.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC)) { + if (file.getType().equals(TSK_DB_FILES_TYPE_ENUM.CARVED)) { + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/carved-file-icon-16.png"); //NON-NLS + } else { + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.png"); //NON-NLS + } + } else { + this.setIconBaseWithExtension(getIconForFileType(file)); + } + } + + @Override + public Action[] getActions(boolean popup) { + List actionsList = new ArrayList<>(); + for (Action a : super.getActions(true)) { + actionsList.add(a); + } + + if (!this.getDirectoryBrowseMode()) { + actionsList.add(new ViewContextAction(NbBundle.getMessage(this.getClass(), "SlackFileNode.viewFileInDir.text"), this.content)); + actionsList.add(null); // creates a menu separator + } + actionsList.add(new NewWindowViewAction( + NbBundle.getMessage(this.getClass(), "SlackFileNode.getActions.viewInNewWin.text"), this)); + actionsList.add(null); // creates a menu separator + actionsList.add(ExtractAction.getInstance()); + actionsList.add(null); // creates a menu separator + actionsList.add(AddContentTagAction.getInstance()); + actionsList.addAll(ContextMenuExtensionPoint.getActions()); + return actionsList.toArray(new Action[actionsList.size()]); + } + + @Override + public T accept(ContentNodeVisitor v) { + return v.visit(this); + } + + @Override + public T accept(DisplayableItemNodeVisitor v) { + return v.visit(this); + } + + // Given a file, returns the correct icon for said + // file based off it's extension + static String getIconForFileType(AbstractFile file) { + + return "org/sleuthkit/autopsy/images/file-icon.png"; //NON-NLS + } + + @Override + public boolean isLeafTypeNode() { + // This seems wrong, but it also seems that it is never called + // because the visitor to figure out if there are children or + // not will check if it has children using the Content API + return true; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index ec66a5d4c7..97d5edf35b 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -45,6 +45,7 @@ import org.sleuthkit.autopsy.datamodel.FileNode; import org.sleuthkit.autopsy.datamodel.LayoutFileNode; import org.sleuthkit.autopsy.datamodel.LocalFileNode; import org.sleuthkit.autopsy.datamodel.Reports; +import org.sleuthkit.autopsy.datamodel.SlackFileNode; import org.sleuthkit.autopsy.datamodel.VirtualDirectoryNode; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -55,6 +56,7 @@ import org.sleuthkit.datamodel.Directory; import org.sleuthkit.datamodel.File; import org.sleuthkit.datamodel.LayoutFile; import org.sleuthkit.datamodel.LocalFile; +import org.sleuthkit.datamodel.SlackFile; import org.sleuthkit.datamodel.TskException; import org.sleuthkit.datamodel.VirtualDirectory; @@ -200,6 +202,8 @@ public class DataResultFilterNode extends FilterNode { } else if ((c = ban.getLookup().lookup(LocalFile.class)) != null || (c = ban.getLookup().lookup(DerivedFile.class)) != null) { n = new LocalFileNode((AbstractFile) c); + } else if ((c = ban.getLookup().lookup(SlackFile.class)) != null) { + n = new SlackFileNode((SlackFile) c); } if (n != null) { actions.add(null); // creates a menu separator diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterChildren.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterChildren.java index e6ce27bc0e..4ea3d721f0 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterChildren.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterChildren.java @@ -31,6 +31,7 @@ import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor; import org.sleuthkit.autopsy.datamodel.FileNode; import org.sleuthkit.autopsy.datamodel.LayoutFileNode; import org.sleuthkit.autopsy.datamodel.LocalFileNode; +import org.sleuthkit.autopsy.datamodel.SlackFileNode; import org.sleuthkit.autopsy.datamodel.VirtualDirectoryNode; import org.sleuthkit.autopsy.datamodel.VolumeNode; import org.sleuthkit.datamodel.AbstractFile; @@ -225,6 +226,11 @@ class DirectoryTreeFilterChildren extends FilterNode.Children { public Boolean visit(LayoutFileNode fn) { return visitDeep(fn); } + + @Override + public Boolean visit(SlackFileNode sfn) { + return visitDeep(sfn); + } @Override public Boolean visit(VolumeNode vn) { @@ -267,6 +273,11 @@ class DirectoryTreeFilterChildren extends FilterNode.Children { public Boolean visit(LayoutFileNode ln) { return ln.hasContentChildren(); } + + @Override + public Boolean visit(SlackFileNode sfn) { + return sfn.hasContentChildren(); + } @Override public Boolean visit(VirtualDirectoryNode vdn) { diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerAction.java index 716ac43005..020178899d 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerAction.java @@ -30,6 +30,7 @@ import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.ContentUtils; +import org.sleuthkit.autopsy.datamodel.SlackFileNode; /** * Extracts a File object to a temporary file in the case directory, and then @@ -68,7 +69,8 @@ public class ExternalViewerAction extends AbstractAction { // no point opening a file if it's empty, and java doesn't know how to // find an application for files without an extension // or if file is executable (for security reasons) - if (!(size > 0) || extPos == -1 || isExecutable) { + // Also skip slack files since their extension is the original extension + "-slack" + if (!(size > 0) || extPos == -1 || isExecutable || (fileNode instanceof SlackFileNode)) { this.setEnabled(false); } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/FileIngestPipeline.java b/Core/src/org/sleuthkit/autopsy/ingest/FileIngestPipeline.java index 99a5c9cf48..1ff48f9351 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/FileIngestPipeline.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/FileIngestPipeline.java @@ -119,7 +119,7 @@ final class FileIngestPipeline { List errors = new ArrayList<>(); if (!this.job.isCancelled()) { AbstractFile file = task.getFile(); - if(file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK)){ // TEMP TEMP + //if(file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK)){ // TEMP TEMP for (PipelineModule module : this.modules) { try { FileIngestPipeline.ingestManager.setIngestTaskProgress(task, module.getDisplayName()); @@ -142,7 +142,7 @@ final class FileIngestPipeline { if (!this.job.isCancelled()) { IngestManager.getInstance().fireFileIngestDone(file); } - }// END TEMP + //}// END TEMP } FileIngestPipeline.ingestManager.setIngestTaskProgressCompleted(task); return errors; diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java index 378c758f16..3adc8cfb6a 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java @@ -207,7 +207,8 @@ public class FileTypeDetector { if (!file.isFile() || file.getSize() <= 0 || (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) || (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) - || (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR)) { + || (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR) + || (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.SLACK)) { mimeType = MimeTypes.OCTET_STREAM; } @@ -289,6 +290,7 @@ public class FileTypeDetector { * posting because general info artifacts are different from other * artifacts, e.g., they are not displayed in the results tree. */ + BlackboardArtifact getInfoArt = file.getGenInfoArtifact(); @SuppressWarnings("deprecation") BlackboardAttribute batt = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FILE_TYPE_SIG, FileTypeIdModuleFactory.getModuleName(), mimeType); diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java index 3cee118c32..8d508a1648 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java @@ -85,11 +85,6 @@ public class FileTypeIdIngestModule implements FileIngestModule { @Override public ProcessResult process(AbstractFile file) { - - //skip slack files - if (file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK)) { - return ProcessResult.OK; - } /** * Attempt to detect the file type. Do it within an exception firewall, diff --git a/Core/src/org/sleuthkit/autopsy/timeline/actions/ViewFileInTimelineAction.java b/Core/src/org/sleuthkit/autopsy/timeline/actions/ViewFileInTimelineAction.java index f90837e1f6..75085293a2 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/actions/ViewFileInTimelineAction.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/actions/ViewFileInTimelineAction.java @@ -24,6 +24,7 @@ import org.openide.util.NbBundle; import org.openide.util.actions.SystemAction; import org.sleuthkit.autopsy.timeline.OpenTimelineAction; import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.TskData; /** * An action to prompt the user to pick an timestamp/event associated with the @@ -38,6 +39,11 @@ public final class ViewFileInTimelineAction extends AbstractAction { private ViewFileInTimelineAction(AbstractFile file, String displayName) { super(displayName); this.file = file; + + if(file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK) + || file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)){ + this.setEnabled(false); + } } @NbBundle.Messages({"ViewFileInTimelineAction.viewFile.displayName=View File in Timeline... "})