Merge remote-tracking branch 'upstream/develop' into improved-case-deletion-part2

This commit is contained in:
Richard Cordovano 2019-03-12 12:51:19 -04:00
commit a854a89e47
50 changed files with 1599 additions and 235 deletions

View File

@ -365,6 +365,7 @@ public class EamArtifactUtil {
case CARVED:
case DERIVED:
case LOCAL:
case LAYOUT_FILE:
return true;
case FS:
return file.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC);

View File

@ -39,7 +39,7 @@ MediaFileViewer.title=Media
MediaFileViewer.toolTip=Displays supported multimedia files (images, videos, audio)
MediaViewImagePanel.errorLabel.OOMText=Could not load file into Media View: insufficent memory.
MediaViewImagePanel.errorLabel.text=Could not load file into Media View.
MediaViewImagePanel.externalViewerButton.text=Open in External Viewer
MediaViewImagePanel.externalViewerButton.text=Open in External Viewer Ctrl+E
MediaViewVideoPanel.pauseButton.text=\u25ba
MediaViewVideoPanel.progressLabel.text=00:00
MediaViewVideoPanel.infoLabel.text=info

View File

@ -60,7 +60,7 @@ import org.sleuthkit.datamodel.AbstractFile;
* Image viewer part of the Media View layered pane. Uses JavaFX to display the
* image.
*/
@NbBundle.Messages({"MediaViewImagePanel.externalViewerButton.text=Open in External Viewer",
@NbBundle.Messages({"MediaViewImagePanel.externalViewerButton.text=Open in External Viewer Ctrl+E",
"MediaViewImagePanel.errorLabel.text=Could not load file into Media View.",
"MediaViewImagePanel.errorLabel.OOMText=Could not load file into Media View: insufficent memory."})
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2018 Basis Technology Corp.
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -38,6 +38,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataResult;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction;
/**
* A DataResultTopComponent object is a NetBeans top component that provides
@ -100,7 +101,7 @@ public final class DataResultTopComponent extends TopComponent implements DataRe
DataResultTopComponent resultViewTopComponent = new DataResultTopComponent(false, title, null, Collections.emptyList(), DataContentTopComponent.findInstance());
initInstance(description, node, childNodeCount, resultViewTopComponent);
return resultViewTopComponent;
}
}
/**
* Creates a result view top component that provides multiple views of the
@ -147,7 +148,7 @@ public final class DataResultTopComponent extends TopComponent implements DataRe
DataResultTopComponent resultViewTopComponent = new DataResultTopComponent(false, title, null, Collections.emptyList(), DataContentTopComponent.findInstance());
return resultViewTopComponent;
}
/**
* Initializes a partially initialized result view top component.
*
@ -248,6 +249,8 @@ public final class DataResultTopComponent extends TopComponent implements DataRe
setName(title);
getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(AddBookmarkTagAction.BOOKMARK_SHORTCUT, "addBookmarkTag"); //NON-NLS
getActionMap().put("addBookmarkTag", new AddBookmarkTagAction()); //NON-NLS
getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ExternalViewerShortcutAction.EXTERNAL_VIEWER_SHORTCUT, "useExternalViewer"); //NON-NLS
getActionMap().put("useExternalViewer", ExternalViewerShortcutAction.getInstance()); //NON-NLS
putClientProperty(TopComponent.PROP_CLOSING_DISABLED, isMain);
putClientProperty(TopComponent.PROP_MAXIMIZATION_DISABLED, true);
putClientProperty(TopComponent.PROP_DRAGGING_DISABLED, true);

View File

@ -22,6 +22,8 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.List;
import java.util.Objects;
@ -31,7 +33,6 @@ import org.openide.nodes.Node;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.CasePreferences;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.SleuthkitCase;
@ -87,6 +88,16 @@ public final class AutopsyTreeChildFactory extends ChildFactory.Detachable<Objec
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
List<DataSource> dataSources = tskCase.getDataSources();
Collections.sort(dataSources, new Comparator<DataSource>() {
@Override
public int compare(DataSource dataS1, DataSource dataS2) {
String dataS1Name = dataS1.getName().toLowerCase();
String dataS2Name = dataS2.getName().toLowerCase();
return dataS1Name.compareTo(dataS2Name);
}
});
List<DataSourceGrouping> keys = new ArrayList<>();
dataSources.forEach((datasource) -> {
keys.add(new DataSourceGrouping(datasource));
@ -140,4 +151,4 @@ public final class AutopsyTreeChildFactory extends ChildFactory.Detachable<Objec
public void refreshChildren() {
refresh(true);
}
}
}

View File

@ -53,7 +53,7 @@ ContentUtils.exception.msg=Cannot extract a {0}
DataModelActionsFactory.srcFileInDir.text=View Source File in Directory
DataModelActionsFactory.fileInDir.text=View File in Directory
DataModelActionsFactory.viewNewWin.text=View in New Window
DataModelActionsFactory.openExtViewer.text=Open in External Viewer
DataModelActionsFactory.openExtViewer.text=Open in External Viewer Ctrl+E
DataSourcesNode.name=Data Sources
DataSourcesNode.group_by_datasource.name=Data Source Files
DataSourcesNode.createSheet.name.name=Name
@ -120,13 +120,13 @@ LayoutFileNode.createSheet.name.displayName=Name
LayoutFileNode.createSheet.name.desc=no description
LayoutFileNode.createSheet.noDescr.text=no description
LayoutFileNode.getActions.viewInNewWin.text=View in New Window
LayoutFileNode.getActions.openInExtViewer.text=Open in External Viewer
LayoutFileNode.getActions.openInExtViewer.text=Open in External Viewer Ctrl+E
LocalFileNode.createSheet.name.name=Name
LocalFileNode.createSheet.name.displayName=Name
LocalFileNode.createSheet.name.desc=no description
LocalFileNode.createSheet.noDescr.text=no description
LocalFileNode.getActions.viewInNewWin.text=View in New Window
LocalFileNode.getActions.openInExtViewer.text=Open in External Viewer
LocalFileNode.getActions.openInExtViewer.text=Open in External Viewer Ctrl+E
LocalFileNode.getActions.searchFilesSameMd5.text=Search for files with the same MD5 hash
OpenReportAction.actionDisplayName=Open Report
OpenReportAction.actionPerformed.MessageBoxTitle=Open Report Failure

View File

@ -95,7 +95,7 @@ DeletedContent.fsDelFilter.text=File System
DeleteReportAction.showConfirmDialog.errorMsg=An error occurred while deleting the reports.
DeleteReportAction.showConfirmDialog.multiple.explanation=The reports will remain on disk.
DeleteReportAction.showConfirmDialog.single.explanation=The report will remain on disk.
FileNode.getActions.openInExtViewer.text=Open in External Viewer
FileNode.getActions.openInExtViewer.text=Open in External Viewer Ctrl+E
FileNode.getActions.searchFilesSameMD5.text=Search for files with the same MD5 hash
FileNode.getActions.viewFileInDir.text=View File in Directory
FileNode.getActions.viewInNewWin.text=View in New Window
@ -210,7 +210,7 @@ ContentUtils.exception.msg=Cannot extract a {0}
DataModelActionsFactory.srcFileInDir.text=View Source File in Directory
DataModelActionsFactory.fileInDir.text=View File in Directory
DataModelActionsFactory.viewNewWin.text=View in New Window
DataModelActionsFactory.openExtViewer.text=Open in External Viewer
DataModelActionsFactory.openExtViewer.text=Open in External Viewer Ctrl+E
DataSourcesNode.name=Data Sources
DataSourcesNode.group_by_datasource.name=Data Source Files
DataSourcesNode.createSheet.name.name=Name
@ -277,13 +277,13 @@ LayoutFileNode.createSheet.name.displayName=Name
LayoutFileNode.createSheet.name.desc=no description
LayoutFileNode.createSheet.noDescr.text=no description
LayoutFileNode.getActions.viewInNewWin.text=View in New Window
LayoutFileNode.getActions.openInExtViewer.text=Open in External Viewer
LayoutFileNode.getActions.openInExtViewer.text=Open in External Viewer Ctrl+E
LocalFileNode.createSheet.name.name=Name
LocalFileNode.createSheet.name.displayName=Name
LocalFileNode.createSheet.name.desc=no description
LocalFileNode.createSheet.noDescr.text=no description
LocalFileNode.getActions.viewInNewWin.text=View in New Window
LocalFileNode.getActions.openInExtViewer.text=Open in External Viewer
LocalFileNode.getActions.openInExtViewer.text=Open in External Viewer Ctrl+E
LocalFileNode.getActions.searchFilesSameMd5.text=Search for files with the same MD5 hash
OpenReportAction.actionDisplayName=Open Report
OpenReportAction.actionPerformed.MessageBoxTitle=Open Report Failure

View File

@ -1,15 +1,15 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2018 Basis Technology Corp.
*
* Copyright 2013-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -37,6 +37,7 @@ import org.sleuthkit.autopsy.actions.ReplaceContentTagAction;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.datamodel.Reports.ReportNode;
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction;
import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
@ -82,7 +83,13 @@ public class DataModelActionsFactory {
final FileNode fileNode = new FileNode(file);
actionsList.add(null); // creates a menu separator
actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, fileNode));
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, fileNode));
final Collection<AbstractFile> selectedFilesList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if (selectedFilesList.size() == 1) {
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, fileNode));
} else {
actionsList.add(ExternalViewerShortcutAction.getInstance());
}
actionsList.add(null); // creates a menu separator
actionsList.add(ExtractAction.getInstance());
actionsList.add(null); // creates a menu separator
@ -90,24 +97,20 @@ public class DataModelActionsFactory {
if (isArtifactSource) {
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
}
final Collection<AbstractFile> selectedFilesList =
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if(selectedFilesList.size() == 1) {
if (selectedFilesList.size() == 1) {
actionsList.add(DeleteFileContentTagAction.getInstance());
}
if(isArtifactSource) {
final Collection<BlackboardArtifact> selectedArtifactsList =
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
if(selectedArtifactsList.size() == 1) {
if (isArtifactSource) {
final Collection<BlackboardArtifact> selectedArtifactsList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
if (selectedArtifactsList.size() == 1) {
actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance());
}
}
actionsList.addAll(ContextMenuExtensionPoint.getActions());
return actionsList;
}
public static List<Action> getActions(SlackFile slackFile, boolean isArtifactSource) {
List<Action> actionsList = new ArrayList<>();
actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), slackFile));
@ -121,20 +124,18 @@ public class DataModelActionsFactory {
if (isArtifactSource) {
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
}
final Collection<AbstractFile> selectedFilesList =
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if(selectedFilesList.size() == 1) {
final Collection<AbstractFile> selectedFilesList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if (selectedFilesList.size() == 1) {
actionsList.add(DeleteFileContentTagAction.getInstance());
}
if(isArtifactSource) {
final Collection<BlackboardArtifact> selectedArtifactsList =
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
if(selectedArtifactsList.size() == 1) {
if (isArtifactSource) {
final Collection<BlackboardArtifact> selectedArtifactsList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
if (selectedArtifactsList.size() == 1) {
actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance());
}
}
actionsList.addAll(ContextMenuExtensionPoint.getActions());
return actionsList;
}
@ -145,7 +146,13 @@ public class DataModelActionsFactory {
LayoutFileNode layoutFileNode = new LayoutFileNode(file);
actionsList.add(null); // creates a menu separator
actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, layoutFileNode));
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, layoutFileNode));
final Collection<AbstractFile> selectedFilesList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if (selectedFilesList.size() == 1) {
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, layoutFileNode));
} else {
actionsList.add(ExternalViewerShortcutAction.getInstance());
}
actionsList.add(null); // creates a menu separator
actionsList.add(ExtractAction.getInstance());//
actionsList.add(null); // creates a menu separator
@ -153,20 +160,16 @@ public class DataModelActionsFactory {
if (isArtifactSource) {
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
}
final Collection<AbstractFile> selectedFilesList =
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if(selectedFilesList.size() == 1) {
if (selectedFilesList.size() == 1) {
actionsList.add(DeleteFileContentTagAction.getInstance());
}
if(isArtifactSource) {
final Collection<BlackboardArtifact> selectedArtifactsList =
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
if(selectedArtifactsList.size() == 1) {
if (isArtifactSource) {
final Collection<BlackboardArtifact> selectedArtifactsList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
if (selectedArtifactsList.size() == 1) {
actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance());
}
}
actionsList.addAll(ContextMenuExtensionPoint.getActions());
return actionsList;
}
@ -177,7 +180,13 @@ public class DataModelActionsFactory {
DirectoryNode directoryNode = new DirectoryNode(directory);
actionsList.add(null); // creates a menu separator
actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, directoryNode));
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, directoryNode));
final Collection<AbstractFile> selectedFilesList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if (selectedFilesList.size() == 1) {
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, directoryNode));
} else {
actionsList.add(ExternalViewerShortcutAction.getInstance());
}
actionsList.add(null); // creates a menu separator
actionsList.add(ExtractAction.getInstance());
actionsList.add(null); // creates a menu separator
@ -185,20 +194,16 @@ public class DataModelActionsFactory {
if (isArtifactSource) {
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
}
final Collection<AbstractFile> selectedFilesList =
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if(selectedFilesList.size() == 1) {
if (selectedFilesList.size() == 1) {
actionsList.add(DeleteFileContentTagAction.getInstance());
}
if(isArtifactSource) {
final Collection<BlackboardArtifact> selectedArtifactsList =
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
if(selectedArtifactsList.size() == 1) {
if (isArtifactSource) {
final Collection<BlackboardArtifact> selectedArtifactsList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
if (selectedArtifactsList.size() == 1) {
actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance());
}
}
actionsList.addAll(ContextMenuExtensionPoint.getActions());
return actionsList;
}
@ -209,7 +214,13 @@ public class DataModelActionsFactory {
VirtualDirectoryNode directoryNode = new VirtualDirectoryNode(directory);
actionsList.add(null); // creates a menu separator
actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, directoryNode));
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, directoryNode));
final Collection<AbstractFile> selectedFilesList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if (selectedFilesList.size() == 1) {
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, directoryNode));
} else {
actionsList.add(ExternalViewerShortcutAction.getInstance());
}
actionsList.add(null); // creates a menu separator
actionsList.add(ExtractAction.getInstance());
actionsList.add(null); // creates a menu separator
@ -217,31 +228,33 @@ public class DataModelActionsFactory {
if (isArtifactSource) {
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
}
final Collection<AbstractFile> selectedFilesList =
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if(selectedFilesList.size() == 1) {
if (selectedFilesList.size() == 1) {
actionsList.add(DeleteFileContentTagAction.getInstance());
}
if(isArtifactSource) {
final Collection<BlackboardArtifact> selectedArtifactsList =
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
if(selectedArtifactsList.size() == 1) {
if (isArtifactSource) {
final Collection<BlackboardArtifact> selectedArtifactsList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
if (selectedArtifactsList.size() == 1) {
actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance());
}
}
actionsList.addAll(ContextMenuExtensionPoint.getActions());
return actionsList;
}
public static List<Action> getActions(LocalDirectory directory, boolean isArtifactSource) {
List<Action> actionsList = new ArrayList<>();
actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), directory));
LocalDirectoryNode directoryNode = new LocalDirectoryNode(directory);
actionsList.add(null); // creates a menu separator
actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, directoryNode));
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, directoryNode));
final Collection<AbstractFile> selectedFilesList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if (selectedFilesList.size() == 1) {
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, directoryNode));
} else {
actionsList.add(ExternalViewerShortcutAction.getInstance());
}
actionsList.add(null); // creates a menu separator
actionsList.add(ExtractAction.getInstance());
actionsList.add(null); // creates a menu separator
@ -249,20 +262,16 @@ public class DataModelActionsFactory {
if (isArtifactSource) {
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
}
final Collection<AbstractFile> selectedFilesList =
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if(selectedFilesList.size() == 1) {
if (selectedFilesList.size() == 1) {
actionsList.add(DeleteFileContentTagAction.getInstance());
}
if(isArtifactSource) {
final Collection<BlackboardArtifact> selectedArtifactsList =
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
if(selectedArtifactsList.size() == 1) {
if (isArtifactSource) {
final Collection<BlackboardArtifact> selectedArtifactsList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
if (selectedArtifactsList.size() == 1) {
actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance());
}
}
actionsList.addAll(ContextMenuExtensionPoint.getActions());
return actionsList;
}
@ -273,7 +282,13 @@ public class DataModelActionsFactory {
final LocalFileNode localFileNode = new LocalFileNode(file);
actionsList.add(null); // creates a menu separator
actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, localFileNode));
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, localFileNode));
final Collection<AbstractFile> selectedFilesList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if (selectedFilesList.size() == 1) {
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, localFileNode));
} else {
actionsList.add(ExternalViewerShortcutAction.getInstance());
}
actionsList.add(null); // creates a menu separator
actionsList.add(ExtractAction.getInstance());
actionsList.add(null); // creates a menu separator
@ -281,20 +296,16 @@ public class DataModelActionsFactory {
if (isArtifactSource) {
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
}
final Collection<AbstractFile> selectedFilesList =
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if(selectedFilesList.size() == 1) {
if (selectedFilesList.size() == 1) {
actionsList.add(DeleteFileContentTagAction.getInstance());
}
if(isArtifactSource) {
final Collection<BlackboardArtifact> selectedArtifactsList =
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
if(selectedArtifactsList.size() == 1) {
if (isArtifactSource) {
final Collection<BlackboardArtifact> selectedArtifactsList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
if (selectedArtifactsList.size() == 1) {
actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance());
}
}
actionsList.addAll(ContextMenuExtensionPoint.getActions());
return actionsList;
}
@ -305,7 +316,13 @@ public class DataModelActionsFactory {
final LocalFileNode localFileNode = new LocalFileNode(file);
actionsList.add(null); // creates a menu separator
actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, localFileNode));
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, localFileNode));
final Collection<AbstractFile> selectedFilesList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if (selectedFilesList.size() == 1) {
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, localFileNode));
} else {
actionsList.add(ExternalViewerShortcutAction.getInstance());
}
actionsList.add(null); // creates a menu separator
actionsList.add(ExtractAction.getInstance());
actionsList.add(null); // creates a menu separator
@ -313,20 +330,16 @@ public class DataModelActionsFactory {
if (isArtifactSource) {
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
}
final Collection<AbstractFile> selectedFilesList =
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if(selectedFilesList.size() == 1) {
if (selectedFilesList.size() == 1) {
actionsList.add(DeleteFileContentTagAction.getInstance());
}
if(isArtifactSource) {
final Collection<BlackboardArtifact> selectedArtifactsList =
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
if(selectedArtifactsList.size() == 1) {
if (isArtifactSource) {
final Collection<BlackboardArtifact> selectedArtifactsList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
if (selectedArtifactsList.size() == 1) {
actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance());
}
}
actionsList.addAll(ContextMenuExtensionPoint.getActions());
return actionsList;
}
@ -340,7 +353,6 @@ public class DataModelActionsFactory {
if (isArtifactSource) {
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
}
if (isArtifactSource) {
final Collection<BlackboardArtifact> selectedArtifactsList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
@ -348,19 +360,23 @@ public class DataModelActionsFactory {
actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance());
}
}
actionsList.addAll(ContextMenuExtensionPoint.getActions());
return actionsList;
}
public static List<Action> getActions(ContentTag contentTag, boolean isArtifactSource) {
List<Action> actionsList = new ArrayList<>();
actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), contentTag.getContent()));
final ContentTagNode tagNode = new ContentTagNode(contentTag);
actionsList.add(null); // creates a menu separator
actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, tagNode));
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, tagNode));
final Collection<AbstractFile> selectedFilesList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if (selectedFilesList.size() == 1) {
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, tagNode));
} else {
actionsList.add(ExternalViewerShortcutAction.getInstance());
}
actionsList.add(null); // creates a menu separator
actionsList.add(ExtractAction.getInstance());
actionsList.add(null); // creates a menu separator
@ -368,35 +384,35 @@ public class DataModelActionsFactory {
if (isArtifactSource) {
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
}
final Collection<AbstractFile> selectedFilesList =
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if(selectedFilesList.size() == 1) {
if (selectedFilesList.size() == 1) {
actionsList.add(DeleteFileContentTagAction.getInstance());
}
if(isArtifactSource) {
final Collection<BlackboardArtifact> selectedArtifactsList =
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
if(selectedArtifactsList.size() == 1) {
if (isArtifactSource) {
final Collection<BlackboardArtifact> selectedArtifactsList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
if (selectedArtifactsList.size() == 1) {
actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance());
}
}
actionsList.add(DeleteContentTagAction.getInstance());
actionsList.add(ReplaceContentTagAction.getInstance());
actionsList.addAll(ContextMenuExtensionPoint.getActions());
return actionsList;
}
public static List<Action> getActions(BlackboardArtifactTag artifactTag, boolean isArtifactSource) {
List<Action> actionsList = new ArrayList<>();
actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), artifactTag.getContent()));
final BlackboardArtifactTagNode tagNode = new BlackboardArtifactTagNode(artifactTag);
actionsList.add(null); // creates a menu separator
actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, tagNode));
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, tagNode));
final Collection<AbstractFile> selectedFilesList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if (selectedFilesList.size() == 1) {
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, tagNode));
} else {
actionsList.add(ExternalViewerShortcutAction.getInstance());
}
actionsList.add(null); // creates a menu separator
actionsList.add(ExtractAction.getInstance());
actionsList.add(null); // creates a menu separator
@ -404,27 +420,22 @@ public class DataModelActionsFactory {
if (isArtifactSource) {
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
}
final Collection<AbstractFile> selectedFilesList =
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if(selectedFilesList.size() == 1) {
if (selectedFilesList.size() == 1) {
actionsList.add(DeleteFileContentTagAction.getInstance());
}
if(isArtifactSource) {
final Collection<BlackboardArtifact> selectedArtifactsList =
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
if(selectedArtifactsList.size() == 1) {
if (isArtifactSource) {
final Collection<BlackboardArtifact> selectedArtifactsList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
if (selectedArtifactsList.size() == 1) {
actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance());
}
}
actionsList.add(DeleteBlackboardArtifactTagAction.getInstance());
actionsList.add(ReplaceBlackboardArtifactTagAction.getInstance());
actionsList.addAll(ContextMenuExtensionPoint.getActions());
return actionsList;
}
public static List<Action> getActions(Content content, boolean isArtifactSource) {
if (content instanceof File) {
return getActions((File) content, isArtifactSource);

View File

@ -23,6 +23,7 @@ import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.List;
import java.util.logging.Level;
@ -123,6 +124,17 @@ public class DataSourcesNode extends DisplayableItemNode {
Content content = Case.getCurrentCaseThrows().getSleuthkitCase().getDataSource(datasourceObjId);
currentKeys = new ArrayList<>(Arrays.asList(content));
}
Collections.sort(currentKeys, new Comparator<Content>() {
@Override
public int compare(Content content1, Content content2) {
String content1Name = content1.getName().toLowerCase();
String content2Name = content2.getName().toLowerCase();
return content1Name.compareTo(content2Name);
}
});
setKeys(currentKeys);
} catch (TskCoreException | NoCurrentCaseException | TskDataException ex) {
logger.log(Level.SEVERE, "Error getting data sources: {0}", ex.getMessage()); // NON-NLS
@ -165,4 +177,4 @@ public class DataSourcesNode extends DisplayableItemNode {
NAME));
return sheet;
}
}
}

View File

@ -424,6 +424,8 @@ public class DeletedContent implements AutopsyVisitableItem {
+ " AND type = " + TskData.TSK_DB_FILES_TYPE_ENUM.FS.getFileType() //NON-NLS
+ " )"
+ " OR type = " + TskData.TSK_DB_FILES_TYPE_ENUM.CARVED.getFileType() //NON-NLS
+ " OR (dir_flags = " + TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue()
+ " AND type = " + TskData.TSK_DB_FILES_TYPE_ENUM.LAYOUT_FILE.getFileType() + " )"
+ " )";
//+ " AND type != " + TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType()
//+ " AND type != " + TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS.getFileType()

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2018 Basis Technology Corp.
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -33,6 +33,7 @@ import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction;
import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
@ -49,9 +50,9 @@ import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM;
* children.
*/
public class FileNode extends AbstractFsContentNode<AbstractFile> {
private static final Logger logger = Logger.getLogger(FileNode.class.getName());
/**
* Gets the path to the icon file that should be used to visually represent
* an AbstractFile, using the file name extension to select the icon.
@ -148,7 +149,7 @@ public class FileNode extends AbstractFsContentNode<AbstractFile> {
@NbBundle.Messages({
"FileNode.getActions.viewFileInDir.text=View File in Directory",
"FileNode.getActions.viewInNewWin.text=View in New Window",
"FileNode.getActions.openInExtViewer.text=Open in External Viewer",
"FileNode.getActions.openInExtViewer.text=Open in External Viewer Ctrl+E",
"FileNode.getActions.searchFilesSameMD5.text=Search for files with the same MD5 hash"})
public Action[] getActions(boolean context) {
List<Action> actionsList = new ArrayList<>();
@ -160,7 +161,14 @@ public class FileNode extends AbstractFsContentNode<AbstractFile> {
}
actionsList.add(new NewWindowViewAction(Bundle.FileNode_getActions_viewInNewWin_text(), this));
actionsList.add(new ExternalViewerAction(Bundle.FileNode_getActions_openInExtViewer_text(), this));
final Collection<AbstractFile> selectedFilesList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if (selectedFilesList.size() == 1) {
actionsList.add(new ExternalViewerAction(
Bundle.FileNode_getActions_openInExtViewer_text(), this));
} else {
actionsList.add(ExternalViewerShortcutAction.getInstance());
}
actionsList.add(ViewFileInTimelineAction.createViewFileAction(getContent()));
actionsList.add(null); // Creates an item separator
@ -168,12 +176,11 @@ public class FileNode extends AbstractFsContentNode<AbstractFile> {
actionsList.add(null); // Creates an item separator
actionsList.add(AddContentTagAction.getInstance());
final Collection<AbstractFile> selectedFilesList = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if (1 == selectedFilesList.size()) {
actionsList.add(DeleteFileContentTagAction.getInstance());
}
actionsList.addAll(ContextMenuExtensionPoint.getActions());
if (FileTypeExtensions.getArchiveExtensions().contains("." + this.content.getNameExtension().toLowerCase())) {
if (FileTypeExtensions.getArchiveExtensions().contains("." + this.content.getNameExtension().toLowerCase())) {
try {
if (this.content.getArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED).size() > 0) {
actionsList.add(new ExtractArchiveWithPasswordAction(this.getContent()));

View File

@ -44,7 +44,6 @@ import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.CasePreferences;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
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;
@ -100,6 +99,7 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
+ TskData.TSK_DB_FILES_TYPE_ENUM.FS.ordinal() + ","
+ TskData.TSK_DB_FILES_TYPE_ENUM.CARVED.ordinal() + ","
+ TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.ordinal() + ","
+ TskData.TSK_DB_FILES_TYPE_ENUM.LAYOUT_FILE.ordinal() + ","
+ TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal()
+ (hideSlackFilesInViewsTree() ? "" : ("," + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal()))
+ "))"

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2018 Basis Technology Corp.
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -23,7 +23,6 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import javax.swing.Action;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
@ -31,6 +30,7 @@ import org.sleuthkit.autopsy.actions.AddContentTagAction;
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction;
import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.datamodel.AbstractFile;
@ -64,6 +64,12 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
if (lf.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.CARVED)) {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/carved-file-icon-16.png"); //NON-NLS
} else if (lf.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.LAYOUT_FILE)) {
if (lf.isDirNameFlagSet(TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC)) {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.png"); //NON-NLS
} else {
this.setIconBaseWithExtension(FileNode.getIconForFileType(lf));
}
} else {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.png"); //NON-NLS
}
@ -89,15 +95,19 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
actionsList.addAll(Arrays.asList(super.getActions(true)));
actionsList.add(new NewWindowViewAction(
NbBundle.getMessage(this.getClass(), "LayoutFileNode.getActions.viewInNewWin.text"), this));
actionsList.add(new ExternalViewerAction(
NbBundle.getMessage(this.getClass(), "LayoutFileNode.getActions.openInExtViewer.text"), this));
final Collection<AbstractFile> selectedFilesList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if (selectedFilesList.size() == 1) {
actionsList.add(new ExternalViewerAction(
NbBundle.getMessage(this.getClass(), "LayoutFileNode.getActions.openInExtViewer.text"), this));
} else {
actionsList.add(ExternalViewerShortcutAction.getInstance());
}
actionsList.add(null); // creates a menu separator
actionsList.add(ExtractAction.getInstance());
actionsList.add(null); // creates a menu separator
actionsList.add(AddContentTagAction.getInstance());
final Collection<AbstractFile> selectedFilesList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if (selectedFilesList.size() == 1) {
actionsList.add(DeleteFileContentTagAction.getInstance());
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2018 Basis Technology Corp.
* Copyright 2013-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -32,6 +32,7 @@ import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction;
import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
@ -61,6 +62,7 @@ public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
}
@Override
public Action[] getActions(boolean context) {
List<Action> actionsList = new ArrayList<>();
actionsList.addAll(Arrays.asList(super.getActions(true)));
@ -69,16 +71,20 @@ public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
actionsList.add(null); // creates a menu separator
actionsList.add(new NewWindowViewAction(
NbBundle.getMessage(this.getClass(), "LocalFileNode.getActions.viewInNewWin.text"), this));
actionsList.add(new ExternalViewerAction(
NbBundle.getMessage(this.getClass(), "LocalFileNode.getActions.openInExtViewer.text"), this));
final Collection<AbstractFile> selectedFilesList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if (selectedFilesList.size() == 1) {
actionsList.add(new ExternalViewerAction(
NbBundle.getMessage(this.getClass(), "LocalFileNode.getActions.openInExtViewer.text"), this));
} else {
actionsList.add(ExternalViewerShortcutAction.getInstance());
}
actionsList.add(null); // creates a menu separator
actionsList.add(ExtractAction.getInstance());
actionsList.add(null); // creates a menu separator
actionsList.add(AddContentTagAction.getInstance());
final Collection<AbstractFile> selectedFilesList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if (selectedFilesList.size() == 1) {
actionsList.add(DeleteFileContentTagAction.getInstance());
}

View File

@ -52,7 +52,7 @@ ChangeViewAction.menuItem.view.string=String
DataResultFilterNode.action.viewFileInDir.text=View File in Directory
DataResultFilterNode.action.viewSrcFileInDir.text=View Source File in Directory
DataResultFilterNode.action.viewInNewWin.text=View in New Window
DataResultFilterNode.action.openInExtViewer.text=Open in External Viewer
DataResultFilterNode.action.openInExtViewer.text=Open in External Viewer Ctrl+E
DataResultFilterNode.action.searchFilesSameMd5.text=Search for files with the same MD5 hash
DataResultFilterNode.action.viewInDir.text=View in Directory
DirectoryTreeFilterNode.action.collapseAll.text=Collapse All

View File

@ -5,12 +5,16 @@ DirectoryTreeTopComponent.componentOpened.groupDataSources.text=This case contai
DirectoryTreeTopComponent.componentOpened.groupDataSources.title=Group by data source?
DirectoryTreeTopComponent.emptyMimeNode.text=Data not available. Run file type identification module.
DirectoryTreeTopComponent.resultsView.title=Listing
ExternalViewerAction.actionPerformed.failure.exe.message=The file is an executable and will not be opened.
ExternalViewerAction.actionPerformed.failure.IO.message=There is no associated editor for files of this type or the associated application failed to launch.
ExternalViewerAction.actionPerformed.failure.missingFile.message=The file no longer exists.
ExternalViewerAction.actionPerformed.failure.open.url=Cannot open URL
ExternalViewerAction.actionPerformed.failure.permission.message=Permission to open the file was denied.
ExternalViewerAction.actionPerformed.failure.support.message=This platform (operating system) does not support opening a file in an editor this way.
ExternalViewerAction.actionPerformed.failure.title=Open File Failure
# {0} - file name
ExternalViewerAction.actionPerformed.failure.title=Open File Failure {0}
ExternalViewerAction.actionPerformed.urlFailure.title=Open URL Failure
ExternalViewerShortcutAction.title.text=Open in External Viewer Ctrl+E
ExtractAction.noOpenCase.errMsg=No open case available.
ExtractUnallocAction.imageError=Error extracting unallocated space from image
ExtractUnallocAction.noFiles=No unallocated files found on volume
@ -80,7 +84,7 @@ ChangeViewAction.menuItem.view.string=String
DataResultFilterNode.action.viewFileInDir.text=View File in Directory
DataResultFilterNode.action.viewSrcFileInDir.text=View Source File in Directory
DataResultFilterNode.action.viewInNewWin.text=View in New Window
DataResultFilterNode.action.openInExtViewer.text=Open in External Viewer
DataResultFilterNode.action.openInExtViewer.text=Open in External Viewer Ctrl+E
DataResultFilterNode.action.searchFilesSameMd5.text=Search for files with the same MD5 hash
DataResultFilterNode.action.viewInDir.text=View in Directory
DirectoryTreeFilterNode.action.collapseAll.text=Collapse All

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2018 Basis Technology Corp.
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -432,19 +432,23 @@ public class DataResultFilterNode extends FilterNode {
actionsList.addAll(DataModelActionsFactory.getActions(c, false));
}
if (n != null) {
final Collection<AbstractFile> selectedFilesList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
actionsList.add(null); // creates a menu separator
actionsList.add(new NewWindowViewAction(
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewInNewWin.text"), n));
actionsList.add(new ExternalViewerAction(
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.openInExtViewer.text"), n));
if (selectedFilesList.size() == 1) {
actionsList.add(new ExternalViewerAction(
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.openInExtViewer.text"), n));
} else {
actionsList.add(ExternalViewerShortcutAction.getInstance());
}
actionsList.add(null); // creates a menu separator
actionsList.add(ExtractAction.getInstance());
actionsList.add(null); // creates a menu separator
actionsList.add(AddContentTagAction.getInstance());
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
final Collection<AbstractFile> selectedFilesList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if (selectedFilesList.size() == 1) {
actionsList.add(DeleteFileContentTagAction.getInstance());
}

View File

@ -1,15 +1,15 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2018 Basis Technology Corp.
*
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -35,6 +35,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.datamodel.SlackFileNode;
import org.sleuthkit.datamodel.AbstractFile;
/**
* Extracts a File object to a temporary file in the case directory, and then
@ -44,24 +45,20 @@ import org.sleuthkit.autopsy.datamodel.SlackFileNode;
public class ExternalViewerAction extends AbstractAction {
private final static Logger logger = Logger.getLogger(ExternalViewerAction.class.getName());
private final org.sleuthkit.datamodel.AbstractFile fileObject;
private final AbstractFile fileObject;
private String fileObjectExt;
final static String[] EXECUTABLE_EXT = {".exe", ".dll", ".com", ".bat", ".msi", ".reg", ".scr", ".cmd"}; //NON-NLS
private boolean isExecutable;
/**
*
* @param title Name of the action
* @param fileNode File to display
*/
public ExternalViewerAction(String title, Node fileNode) {
ExternalViewerAction(String title, AbstractFile file, boolean isSlackFile) {
super(title);
this.fileObject = fileNode.getLookup().lookup(org.sleuthkit.datamodel.AbstractFile.class);
this.fileObject = file;
long size = fileObject.getSize();
String fileName = fileObject.getName();
int extPos = fileName.lastIndexOf('.');
boolean isExecutable = false;
isExecutable = false;
if (extPos != -1) {
String extension = fileName.substring(extPos, fileName.length()).toLowerCase();
fileObjectExt = extension;
@ -79,13 +76,35 @@ public class ExternalViewerAction extends AbstractAction {
// find an application for files without an extension
// or if file is executable (for security reasons)
// Also skip slack files since their extension is the original extension + "-slack"
if (!(size > 0) || extPos == -1 || isExecutable || (fileNode instanceof SlackFileNode)) {
if (!(size > 0) || extPos == -1 || isExecutable || isSlackFile) {
this.setEnabled(false);
}
}
/**
*
* @param title Name of the action
* @param fileNode File to display
*/
public ExternalViewerAction(String title, Node fileNode) {
this(title, fileNode.getLookup().lookup(org.sleuthkit.datamodel.AbstractFile.class), fileNode instanceof SlackFileNode);
}
@Override
@Messages({
"# {0} - file name",
"ExternalViewerAction.actionPerformed.failure.title=Open File Failure {0}",
"ExternalViewerAction.actionPerformed.failure.exe.message=The file is an executable and will not be opened."
})
public void actionPerformed(ActionEvent e) {
if (isExecutable) {
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
Bundle.ExternalViewerAction_actionPerformed_failure_exe_message(),
Bundle.ExternalViewerAction_actionPerformed_failure_title(this.fileObject.getName()),
JOptionPane.ERROR_MESSAGE);
return;
}
// Get the temp folder path of the case
Case openCase;
try {
@ -124,7 +143,6 @@ public class ExternalViewerAction extends AbstractAction {
* @param file the file object
*/
@Messages({
"ExternalViewerAction.actionPerformed.failure.title=Open File Failure",
"ExternalViewerAction.actionPerformed.failure.IO.message=There is no associated editor for files of this type or the associated application failed to launch.",
"ExternalViewerAction.actionPerformed.failure.support.message=This platform (operating system) does not support opening a file in an editor this way.",
"ExternalViewerAction.actionPerformed.failure.missingFile.message=The file no longer exists.",
@ -146,14 +164,14 @@ public class ExternalViewerAction extends AbstractAction {
runtime.exec(execArray);
} catch (IOException ex) {
logger.log(Level.WARNING, "Could not open the specified viewer for the given file: " + file.getName(), ex); //NON-NLS
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), Bundle.ExternalViewerAction_actionPerformed_failure_IO_message(), Bundle.ExternalViewerAction_actionPerformed_failure_title(), JOptionPane.ERROR_MESSAGE);
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), Bundle.ExternalViewerAction_actionPerformed_failure_IO_message(), Bundle.ExternalViewerAction_actionPerformed_failure_title(file.getName()), JOptionPane.ERROR_MESSAGE);
}
} else {
try {
String localpath = file.getPath();
if (localpath.toLowerCase().contains("http")) {
String url_path = file.getPath().replaceAll("\\\\","/");
Desktop.getDesktop().browse(new URI(url_path.replaceFirst("/","//")));
String url_path = file.getPath().replaceAll("\\\\", "/");
Desktop.getDesktop().browse(new URI(url_path.replaceFirst("/", "//")));
} else {
Desktop.getDesktop().open(file);
}
@ -162,75 +180,77 @@ public class ExternalViewerAction extends AbstractAction {
logger.log(Level.WARNING, "Could not find a viewer for the given file: " + file.getName(), ex); //NON-NLS
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
Bundle.ExternalViewerAction_actionPerformed_failure_IO_message(),
Bundle.ExternalViewerAction_actionPerformed_failure_title(),
Bundle.ExternalViewerAction_actionPerformed_failure_title(file.getName()),
JOptionPane.ERROR_MESSAGE);
} catch (UnsupportedOperationException ex) {
logger.log(Level.WARNING, "Platform cannot open " + file.getName() + " in the defined editor.", ex); //NON-NLS
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
Bundle.ExternalViewerAction_actionPerformed_failure_support_message(),
Bundle.ExternalViewerAction_actionPerformed_failure_title(),
Bundle.ExternalViewerAction_actionPerformed_failure_title(file.getName()),
JOptionPane.ERROR_MESSAGE);
} catch (IllegalArgumentException ex) {
logger.log(Level.WARNING, "Could not find the given file: " + file.getName(), ex); //NON-NLS
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
Bundle.ExternalViewerAction_actionPerformed_failure_missingFile_message(),
Bundle.ExternalViewerAction_actionPerformed_failure_title(),
Bundle.ExternalViewerAction_actionPerformed_failure_title(file.getName()),
JOptionPane.ERROR_MESSAGE);
} catch (SecurityException ex) {
logger.log(Level.WARNING, "Could not get permission to open the given file: " + file.getName(), ex); //NON-NLS
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
Bundle.ExternalViewerAction_actionPerformed_failure_permission_message(),
Bundle.ExternalViewerAction_actionPerformed_failure_title(),
Bundle.ExternalViewerAction_actionPerformed_failure_title(file.getName()),
JOptionPane.ERROR_MESSAGE);
} catch (URISyntaxException ex) {
logger.log(Level.WARNING, "Could not open URL provided: " + file.getPath(), ex);
JOptionPane.showMessageDialog(null,
Bundle.ExternalViewerAction_actionPerformed_failure_open_url(),
Bundle.ExternalViewerAction_actionPerformed_failure_title(),
JOptionPane.ERROR_MESSAGE);
logger.log(Level.WARNING, "Could not open URL provided: " + file.getPath(), ex);
JOptionPane.showMessageDialog(null,
Bundle.ExternalViewerAction_actionPerformed_failure_open_url(),
Bundle.ExternalViewerAction_actionPerformed_failure_title(file.getName()),
JOptionPane.ERROR_MESSAGE);
}
}
}
/**
* Opens a URL using the default desktop browser
*
* @param path URL to open
*
* @param path URL to open
*/
@Messages({
"ExternalViewerAction.actionPerformed.urlFailure.title=Open URL Failure"})
public static void openURL(String path) {
String url_path = path.replaceAll("\\\\","/");
String url_path = path.replaceAll("\\\\", "/");
try {
Desktop.getDesktop().browse(new URI(url_path.replaceFirst("/","//")));
Desktop.getDesktop().browse(new URI(url_path.replaceFirst("/", "//")));
} catch (IOException ex) {
logger.log(Level.WARNING, "Could not find a viewer for the given URL: " + url_path, ex); //NON-NLS
JOptionPane.showMessageDialog(null,
Bundle.ExternalViewerAction_actionPerformed_failure_IO_message(),
Bundle.ExternalViewerAction_actionPerformed_failure_title(),
Bundle.ExternalViewerAction_actionPerformed_urlFailure_title(),
JOptionPane.ERROR_MESSAGE);
} catch (UnsupportedOperationException ex) {
logger.log(Level.WARNING, "Platform cannot open " + url_path + " in the defined editor.", ex); //NON-NLS
JOptionPane.showMessageDialog(null,
Bundle.ExternalViewerAction_actionPerformed_failure_support_message(),
Bundle.ExternalViewerAction_actionPerformed_failure_title(),
Bundle.ExternalViewerAction_actionPerformed_urlFailure_title(),
JOptionPane.ERROR_MESSAGE);
} catch (IllegalArgumentException ex) {
logger.log(Level.WARNING, "Could not find the given URL: " + url_path, ex); //NON-NLS
JOptionPane.showMessageDialog(null,
Bundle.ExternalViewerAction_actionPerformed_failure_missingFile_message(),
Bundle.ExternalViewerAction_actionPerformed_failure_title(),
Bundle.ExternalViewerAction_actionPerformed_urlFailure_title(),
JOptionPane.ERROR_MESSAGE);
} catch (SecurityException ex) {
logger.log(Level.WARNING, "Could not get permission to open the given URL: " + url_path, ex); //NON-NLS
JOptionPane.showMessageDialog(null,
Bundle.ExternalViewerAction_actionPerformed_failure_permission_message(),
Bundle.ExternalViewerAction_actionPerformed_failure_title(),
Bundle.ExternalViewerAction_actionPerformed_urlFailure_title(),
JOptionPane.ERROR_MESSAGE);
} catch (URISyntaxException ex) {
logger.log(Level.WARNING, "Could not open URL provided: " + url_path, ex);
JOptionPane.showMessageDialog(null,
Bundle.ExternalViewerAction_actionPerformed_failure_open_url(),
Bundle.ExternalViewerAction_actionPerformed_failure_title(),
JOptionPane.ERROR_MESSAGE);
logger.log(Level.WARNING, "Could not open URL provided: " + url_path, ex);
JOptionPane.showMessageDialog(null,
Bundle.ExternalViewerAction_actionPerformed_failure_open_url(),
Bundle.ExternalViewerAction_actionPerformed_urlFailure_title(),
JOptionPane.ERROR_MESSAGE);
}
}
}

View File

@ -0,0 +1,68 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.directorytree;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.Collection;
import java.util.HashSet;
import javax.swing.AbstractAction;
import javax.swing.KeyStroke;
import org.openide.util.NbBundle.Messages;
import org.openide.util.Utilities;
import org.sleuthkit.datamodel.AbstractFile;
/**
* Extracts a File object to a temporary file in the case directory, and then
* tries to open it in the user's system with the default or user specified
* associated application.
*/
@Messages({"ExternalViewerShortcutAction.title.text=Open in External Viewer Ctrl+E"})
public class ExternalViewerShortcutAction extends AbstractAction {
public static final KeyStroke EXTERNAL_VIEWER_SHORTCUT = KeyStroke.getKeyStroke(KeyEvent.VK_E, InputEvent.CTRL_MASK);
private ExternalViewerShortcutAction() {
super(Bundle.ExternalViewerShortcutAction_title_text());
}
// This class is a singleton to support multi-selection of nodes, since
// org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every
// node in the array returns a reference to the same action object from Node.getActions(boolean).
private static ExternalViewerShortcutAction instance;
public static synchronized ExternalViewerShortcutAction getInstance() {
if (null == instance) {
instance = new ExternalViewerShortcutAction();
}
return instance;
}
@Override
public void actionPerformed(ActionEvent e) {
final Collection<AbstractFile> selectedFiles = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if (!selectedFiles.isEmpty()) {
for (AbstractFile file : selectedFiles) {
ExternalViewerAction action = new ExternalViewerAction(Bundle.ExternalViewerShortcutAction_title_text(), file, false);
action.actionPerformed(e);
}
}
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2018 Basis Technology Corp.
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -65,6 +65,7 @@ import org.sleuthkit.autopsy.corecomponents.DataResultPanel;
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction;
import org.sleuthkit.autopsy.timeline.actions.Back;
import org.sleuthkit.autopsy.timeline.actions.Forward;
import org.sleuthkit.autopsy.timeline.explorernodes.EventNode;
@ -103,7 +104,9 @@ public final class TimeLineTopComponent extends TopComponent implements Explorer
private final TimeLineController controller;
/** Lookup that will be exposed through the (Global Actions Context) */
/**
* Lookup that will be exposed through the (Global Actions Context)
*/
private final ModifiableProxyLookup proxyLookup = new ModifiableProxyLookup();
private final PropertyChangeListener focusPropertyListener = new PropertyChangeListener() {
@ -261,7 +264,8 @@ public final class TimeLineTopComponent extends TopComponent implements Explorer
getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(AddBookmarkTagAction.BOOKMARK_SHORTCUT, "addBookmarkTag"); //NON-NLS
getActionMap().put("addBookmarkTag", new AddBookmarkTagAction()); //NON-NLS
getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ExternalViewerShortcutAction.EXTERNAL_VIEWER_SHORTCUT, "useExternalViewer"); //NON-NLS
getActionMap().put("useExternalViewer", ExternalViewerShortcutAction.getInstance()); //NON-NLS
this.controller = controller;
//create linked result and content views

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2018 Basis Technology Corp.
* Copyright 2013-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -50,6 +50,7 @@ import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Modality;
import javax.annotation.concurrent.GuardedBy;
import javax.swing.JComponent;
import javax.swing.SwingUtilities;
import static org.apache.commons.collections4.CollectionUtils.isNotEmpty;
import static org.apache.commons.lang3.ObjectUtils.notEqual;
@ -64,6 +65,7 @@ import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction;
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute;
import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupManager;
import org.sleuthkit.autopsy.imagegallery.gui.DataSourceCell;
@ -238,6 +240,8 @@ public final class ImageGalleryTopComponent extends TopComponent implements Expl
public ImageGalleryTopComponent() {
setName(Bundle.CTL_ImageGalleryTopComponent());
initComponents();
getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ExternalViewerShortcutAction.EXTERNAL_VIEWER_SHORTCUT, "useExternalViewer"); //NON-NLS
getActionMap().put("useExternalViewer", ExternalViewerShortcutAction.getInstance()); //NON-NLS
}
/**

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2015 Basis Technology Corp.
* Copyright 2015-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -21,6 +21,9 @@ package org.sleuthkit.autopsy.imagegallery.actions;
import java.awt.event.ActionEvent;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
import javax.swing.SwingUtilities;
import org.controlsfx.control.action.Action;
import org.openide.util.NbBundle;
@ -33,10 +36,11 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile;
* appropriate text and graphic
*/
@NbBundle.Messages({"MediaViewImagePanel.externalViewerButton.text=Open in External Viewer",
"OpenExternalViewerAction.displayName=External Viewer"})
"OpenExternalViewerAction.displayName=External Viewer"})
public class OpenExternalViewerAction extends Action {
private static final Image EXTERNAL = new Image(OpenExternalViewerAction.class.getResource("/org/sleuthkit/autopsy/imagegallery/images/external.png").toExternalForm()); //NON-NLS
public static final KeyCombination EXTERNAL_VIEWER_SHORTCUT = new KeyCodeCombination(KeyCode.E, KeyCombination.CONTROL_DOWN);
private static final ActionEvent ACTION_EVENT = new ActionEvent(OpenExternalViewerAction.class, ActionEvent.ACTION_PERFORMED, ""); //Swing ActionEvent //NOI18N
public OpenExternalViewerAction(DrawableFile file) {
@ -49,9 +53,12 @@ public class OpenExternalViewerAction extends Action {
ExternalViewerAction externalViewerAction = new ExternalViewerAction(Bundle.MediaViewImagePanel_externalViewerButton_text(), new FileNode(file.getAbstractFile()));
setLongText(Bundle.MediaViewImagePanel_externalViewerButton_text());
setEventHandler(actionEvent -> //fx ActionEvent
setEventHandler(actionEvent
-> //fx ActionEvent
SwingUtilities.invokeLater(() -> externalViewerAction.actionPerformed(ACTION_EVENT))
);
setGraphic(new ImageView(EXTERNAL));
setAccelerator(EXTERNAL_VIEWER_SHORTCUT);
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2018 Basis Technology Corp.
* Copyright 2013-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -47,7 +47,6 @@ import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import javax.swing.Action;
import javax.swing.SwingUtilities;
import org.controlsfx.control.action.ActionUtils;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
@ -60,6 +59,7 @@ import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent;
import org.sleuthkit.autopsy.corecomponentinterfaces.ContextMenuActionsProvider;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.FileNode;
import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction;
import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel;
@ -214,11 +214,13 @@ public abstract class DrawableTileBase extends DrawableUIBase {
.actionPerformed(null);
}));
menuItems.add(contentViewer);
OpenExternalViewerAction openExternalViewerAction = new OpenExternalViewerAction(file);
MenuItem externalViewer = ActionUtils.createMenuItem(openExternalViewerAction);
externalViewer.textProperty().unbind();
externalViewer.textProperty().bind(openExternalViewerAction.longTextProperty());
MenuItem externalViewer = new MenuItem("Open in External Viewer");
externalViewer.setOnAction(actionEvent
-> SwingUtilities.invokeLater(() -> {
ExternalViewerShortcutAction.getInstance()
.actionPerformed(null);
}));
externalViewer.setAccelerator(OpenExternalViewerAction.EXTERNAL_VIEWER_SHORTCUT);
menuItems.add(externalViewer);
Collection<? extends ContextMenuActionsProvider> menuProviders = Lookup.getDefault().lookupAll(ContextMenuActionsProvider.class);
@ -346,7 +348,7 @@ public abstract class DrawableTileBase extends DrawableUIBase {
final TagName followUpTagName = getController().getTagsManager().getFollowUpTagName(); //NON-NLS
final ContentTag addedTag = evt.getAddedTag();
if (fileID == addedTag.getContent().getId()
&& addedTag.getName().equals(followUpTagName)) {
&& addedTag.getName().equals(followUpTagName)) {
Platform.runLater(() -> {
followUpImageView.setImage(followUpIcon);
followUpToggle.setSelected(true);
@ -362,7 +364,7 @@ public abstract class DrawableTileBase extends DrawableUIBase {
final TagName followUpTagName = getController().getTagsManager().getFollowUpTagName(); //NON-NLS
final ContentTagDeletedEvent.DeletedContentTagInfo deletedTagInfo = evt.getDeletedTagInfo();
if (fileID == deletedTagInfo.getContentID()
&& deletedTagInfo.getName().equals(followUpTagName)) {
&& deletedTagInfo.getName().equals(followUpTagName)) {
updateFollowUpIcon();
}
});

View File

@ -1,4 +1,5 @@
OpenIDE-Module-Display-Category=Ingest Module
OpenIDE-Module-Long-Description=Keyword Search ingest module.\n\nThe module indexes files found in the disk image at ingest time.\nIt then periodically runs the search on the indexed files using one or more keyword lists (containing pure words and/or regular expressions) and posts results.\n\n\The module also contains additional tools integrated in the main GUI, such as keyword list configuration, keyword search bar in the top-right corner, extracted text viewer and search results viewer showing highlighted keywords found.
OpenIDE-Module-Name=KeywordSearch
OptionsCategory_Name_KeywordSearchOptions=Keyword Search
@ -87,7 +88,7 @@ KeywordSearchEditListPanel.exportButtonActionPerformed.kwListExportedMsg=Keyword
KeywordSearchEditListPanel.kwColName=Keyword
KeywordSearchEditListPanel.addKeyword.message=Add a new word to the keyword search list:
KeywordSearchEditListPanel.addKeyword.title=New Keyword
KeywordSearchFilterNode.getFileActions.openExternViewActLbl=Open in External Viewer
KeywordSearchFilterNode.getFileActions.openExternViewActLbl=Open in External Viewer Ctrl+E
KeywordSearchFilterNode.getFileActions.searchSameMd5=Search for files with the same MD5 hash
KeywordSearchFilterNode.getFileActions.viewInNewWinActionLbl=View in New Window
KeywordSearchIngestModule.init.noKwInLstMsg=No keywords in keyword list.

View File

@ -122,7 +122,7 @@ KeywordSearchEditListPanel.exportButtonActionPerformed.kwListExportedMsg=Keyword
KeywordSearchEditListPanel.kwColName=Keyword
KeywordSearchEditListPanel.addKeyword.message=Add a new word to the keyword search list:
KeywordSearchEditListPanel.addKeyword.title=New Keyword
KeywordSearchFilterNode.getFileActions.openExternViewActLbl=Open in External Viewer
KeywordSearchFilterNode.getFileActions.openExternViewActLbl=Open in External Viewer Ctrl+E
KeywordSearchFilterNode.getFileActions.searchSameMd5=Search for files with the same MD5 hash
KeywordSearchFilterNode.getFileActions.viewInNewWinActionLbl=View in New Window
KeywordSearchIngestModule.init.noKwInLstMsg=No keywords in keyword list.

View File

@ -0,0 +1,287 @@
;==============================================================================
; Autopsy Forensic Browser
;
; Copyright 2019 Basis Technology Corp.
; Contact: carrier <at> sleuthkit <dot> org
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
; http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;==============================================================================
#include <GUIConstantsEx.au3>
#include <MsgBoxConstants.au3>
#include <ProgressConstants.au3>
#include <File.au3>
#include <WinAPIFiles.au3>
#include <ScrollBarConstants.au3>
#include <GuiEdit.au3>
#include <Date.au3>
;Get the list of names of algorithms
Global $algorithms[3] ;increase size of array when adding new algorithms
$algorithms[0] = "Single Data Source"
$algorithms[1] = "Folder of Logical Files"
$algorithms[2] = "One Data Source Per Folder"
; $algorithms[2] = "All Files In One Folder"
Global $progressArea = Null
Global $manifestFileNameEnd = "Manifest"
Global $manifestExtension = ".xml"
;Return an array containing the names of all algorithms
Func GetAlgorithmNames()
Return $algorithms
EndFunc
;Return the name of the first algorithm as a default algorithm
Func GetDefaultAlgorithmName()
Return $algorithms[0]
EndFunc
;Run the function that corresponds to the specified Algorithm name
;Use Null for $progressArea if not called from a GUI with a $progressArea
Func RunAlgorithm($selectedAlgorithm, $settings, ByRef $progressAreaRef)
$progressArea = $progressAreaRef
UpdateProgressArea("Analyzing: " & $settings[0])
if ($selectedAlgorithm == $algorithms[2]) Then
OneDataSourcePerFolder($settings)
ElseIf ($selectedAlgorithm == $algorithms[0]) Then
SingleDataSource($settings)
ElseIf ($selectedAlgorithm == $algorithms[1]) Then
SingleDataSource($settings)
; ElseIf ($selectedAlgorithm == $algorithms[2]) Then
; AllFilesInOneFolder($settings)
EndIf
UpdateProgressArea("-------------------------------------------------------------------------------------------") ;blank line for some
EndFunc
;Create a manifest file in the specified $caseDir named $manifestDir _Manifest.xml
;if the $manifestFile is specified the datasource included will be the file instead of the entire folder
Func GenerateCaseNameAndWriteManifestFile($caseDir, $subDirName, $manifestFile)
Local $manifestName = ""
Local $caseName = ""
Local $dataSourcePath = ""
;If the manifestDirectory is not Null use it for the file name
if ($subDirName <> Null) Then
$manifestName = $subDirName
$dataSourcePath = $manifestName
if ($manifestFile <> Null) Then
$dataSourcePath = $dataSourcePath & "\" & $manifestFile
EndIf
;If the manifestDirectory was Null then use the file name
ElseIf ($manifestFile <> Null) Then
$manifestName = $manifestFile
$dataSourcePath = $manifestName
Else
UpdateProgressArea("ERROR: Invalid arguements provided, unable to create manifest file")
Return
EndIf
Local $splitCaseDir = StringSplit($caseDir, "\", $STR_ENTIRESPLIT)
$caseName = $splitCaseDir[$splitCaseDir[0]]
Local $manfiestFilePath = $caseDir & "\" & $manifestName & "_" & $manifestFileNameEnd & $manifestExtension
WriteManifestFile($manfiestFilePath, $manifestName, $caseName, $dataSourcePath)
EndFunc
;Write the specified manifest file.
Func WriteManifestFile($manifestFilePath, $manifestName, $caseName, $dataSourcePath)
_FileCreate($manifestFilePath)
Local $fileHandle = FileOpen($manifestFilePath, $FO_APPEND)
If $fileHandle == -1 Then
UpdateProgressArea("ERROR: " & $manifestName & " Unable to create manifest file")
Return
EndIf
FileWrite($fileHandle,'<?xml version="1.0" encoding="UTF-8" standalone="no"?>' & @CRLF)
FileWrite($fileHandle,'<AutopsyManifest>' & @CRLF)
FileWrite($fileHandle,'<CaseName>' & $caseName &'</CaseName>' & @CRLF)
;Device ID is not a required field
FileWrite($fileHandle,'<DataSource>' & $dataSourcePath & '</DataSource>' & @CRLF)
FileWrite($fileHandle,'</AutopsyManifest>' & @CRLF)
FileClose($fileHandle)
UpdateProgressArea($manifestName & " manifest created")
EndFunc
;get the extension of a file
Func GetFileExtension($fileName)
Local $fileExtension
_PathSplit ($fileName, "", "", "", $fileExtension)
Return $fileExtension
EndFunc
;Return 0 for false if no manifest files exist in the caseDir, or 1 for true if manifest files do exist
Func ManifestFilesAlreadyExist($fileList)
Local $fileName
Local $fileExtension
For $i = 1 To $fileList[0] Step 1
_PathSplit ($fileList[$i], "", "", $fileName, $fileExtension)
If StringCompare($fileExtension, $manifestExtension, $STR_NOCASESENSE) == 0 Then
Local $splitFileName = StringSplit($fileName, "_", $STR_ENTIRESPLIT)
if $splitFileName[0] > 1 Then ;It split into more than one chunk so the last chunk should match our _Manifest
If StringCompare($splitFileName[$splitFileName[0]], $manifestFileNameEnd, $STR_NOCASESENSE) == 0 Then
UpdateProgressArea("Folder already contains manifest file: " & $fileList[$i])
Return 1
EndIf
EndIf
EndIf
Next
Return 0
EndFunc
;Check if a manifest file already exists for a specific datasource in the case Dir
;Return 1 if a manifest exists
;Return 0 if no manifest exists
Func ManifestAlreadyExists($manifestFilePath)
If FileExists($manifestFilePath) == 1 Then
Return 1
Else
Return 0
EndIf
EndFunc
;Algorithm for the "One Data Source Per Folder"
;Creates manifest files
Func OneDataSourcePerFolder($settings)
Local $validDirectory = 1
Local $caseDir = $settings[0]
;_FileListToArray returns the count of files/folders as the first value then the contents
Local $fileList = _FileListToArray($caseDir, Default, $FLTA_FILES, False)
Local $caseDirSplit = StringSplit($caseDir, "\", $STR_ENTIRESPLIT)
Local $caseDirName
if ($caseDirSplit[0] > 1) Then
;if case folder is longer than one directory display just the directory name in progress messages
$caseDirName = $caseDirSplit[$caseDirSplit[0]]
Else
;if there is only one directory use the entire case dir path
EndIf
If (@error == 1) Then
$validDirectory = 0
UpdateProgressArea("ERROR: " & $caseDirName & " not found")
MsgBox($MB_OK, "Directory Not Found", "Selected directory " & $caseDirName & " was not found.")
ElseIf (@error > 0) Then
;An acceptable condition as no files means no manifest files
EndIf
Local $dirList = _FileListToArray($caseDir, Default, $FLTA_FOLDERS, True)
If (@error ==4) Then
UpdateProgressArea($caseDirName & " no folders found")
MsgBox($MB_OK, "Selected Directory Empty", "Selected directory " & $caseDirName & " did not contain any subfolders to use as data sources for manifest files.")
$validDirectory = 0
EndIf
If $validDirectory = 1 Then
Local $validExtensions[4] = [".e01", ".l01", ".001", ".ad1"] ;valid extensions for the One Data Source Per Folder algorithm
Local $subDirectoryFileList
Local $validSubDirectory
For $fileNumber = 1 TO $dirList[0] Step 1
Local $manifestFile = Null
Local $manifestDir = $dirList[$fileNumber]
Local $splitManifestDir = StringSplit($manifestDir, "\", $STR_ENTIRESPLIT)
Local $manifestDirName = $splitManifestDir[$splitManifestDir[0]]
$subDirectoryFileList = _FileListToArray($dirList[$fileNumber], Default, Default, False)
$validSubDirectory = 1
If (@error == 1) Then
$validSubDirectory = 0
UpdateProgressArea("ERROR: " & $dirList[$fileNumber] & " not found")
ElseIf (@error ==4) Then
UpdateProgressArea($manifestDirName & " empty, no manifest created")
$validSubDirectory = 0
EndIf
If $validSubDirectory == 1 Then
For $i = 1 TO $subDirectoryFileList[0] Step 1
Local $currentFilesExtension = GetFileExtension($subDirectoryFileList[$i])
For $extension IN $validExtensions
;should only be one file or directory in this folder since we checked the number of contents previously
If StringCompare($extension, $currentFilesExtension, $STR_NOCASESENSE) == 0 Then
$manifestFile = $subDirectoryFileList[$i]
ExitLoop 2 ;match was found no reason to check remaining extensions or files in a One Data Source Per Folder algorithm
EndIf
Next
Next
Local $manifestFilePath = $caseDir & "\" & $manifestDirName & "_" & $manifestFileNameEnd & $manifestExtension
If (ManifestAlreadyExists($manifestFilePath) <> 1) Then
;should only be one file and it should end with a valid extension add as image file, or the whole directory is added as a logical file set
GenerateCaseNameAndWriteManifestFile($caseDir, $manifestDirName, $manifestFile)
Else
UpdateProgressArea($manifestDirName & " manifest exists, skipping")
EndIf
EndIf
Next
UpdateProgressArea($caseDirName & " manifest generation complete")
EndIf
EndFunc
;Create a manifest file for a single data source in the same directory that contains the data source (also used for Folder of Logical Files)
Func SingleDataSource($settings)
Local $dataSourcePath = $settings[0]
Local $caseDir = ""
Local $caseDrive = ""
Local $dsName = ""
Local $dsExtension = ""
_PathSplit ($dataSourcePath, $caseDrive, $caseDir, $dsName, $dsExtension)
$caseDir = $caseDrive & $caseDir
Local $caseName = $settings[1]
Local $manfiestFilePath = $caseDir & "\" & $dsName & "_" & $manifestFileNameEnd & $manifestExtension
If (ManifestAlreadyExists($manfiestFilePath) <> 1) Then
;should only be one file and it should end with a valid extension add as image file, or the whole directory is added as a logical file set
WriteManifestFile($manfiestFilePath, $dsName, $caseName, $dsName & $dsExtension)
Else
UpdateProgressArea($dsName & " manifest exists, skipping")
EndIf
EndFunc
;Algorithm for the All Files in One Folder
;Creates manifest files for all files and directories in a single directory
Func AllFilesInOneFolder($settings)
Local $validDirectory = 1
Local $caseDir = $settings[0]
;_FileListToArray returns the count of files/folders as the first value then the contents
Local $fileList = _FileListToArray($caseDir, Default, $FLTA_FILES, False)
If (@error == 1) Then
$validDirectory = 0
UpdateProgressArea("Selected directory " & $caseDir & " was not found")
MsgBox($MB_OK, "Directory Not Found", "Selected directory " & $caseDir & " was not found")
ElseIf (@error > 0) Then
Local $dirList = _FileListToArray($caseDir, Default, $FLTA_FOLDERS, True)
If (@error ==4) Then
UpdateProgressArea("Selected directory " & $caseDir & " was empty and contained nothing to generate manifest files for")
MsgBox($MB_OK, "Selected Directory Empty", "Selected directory " & $caseDir & " was empty and contained nothing to generate manifest files for")
$validDirectory = 0
EndIf
;An acceptable condition as no files means no manifest files
ElseIf ManifestFilesAlreadyExist($fileList) == 1 Then
UpdateProgressArea("Selected directory " & $caseDir & " already contains manifest files, they must be deleted before generating new ones")
MsgBox($MB_OK, "Manifest Files Exist", "Selected directory " & $caseDir & " already contains manifest files, they must be deleted before generating new ones")
$validDirectory = 0
EndIf
Local $contentsList = _FileListToArray ($caseDir, Default, Default, False)
If $validDirectory = 1 Then
For $fileNumber = 1 TO $contentsList[0] Step 1
Local $manifestDir = Null
Local $manifestFile = $contentsList[$fileNumber]
GenerateCaseNameAndWriteManifestFile($caseDir, $manifestDir, $manifestFile)
Next
UpdateProgressArea($caseDir & " manifest generation complete")
EndIf
EndFunc
;If the progress area is Null it will not be updated
Func UpdateProgressArea($textToAdd)
if ($progressArea <> Null) Then
Local $currentProgressAreaText = GUICtrlRead($progressArea)
$currentProgressAreaText = $currentProgressAreaText & @CRLF & "--" & $textToAdd
GUICtrlSetData($progressArea, $currentProgressAreaText)
_GUICtrlEdit_Scroll($progressArea, $SB_SCROLLCARET)
EndIf
EndFunc

View File

@ -0,0 +1,316 @@
;==============================================================================
; Autopsy Forensic Browser
;
; Copyright 2019 Basis Technology Corp.
; Contact: carrier <at> sleuthkit <dot> org
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
; http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;==============================================================================
#include <GUIConstantsEx.au3>
#include <MsgBoxConstants.au3>
#include<ComboConstants.au3>
#include <EditConstants.au3>
#include<WindowsConstants.au3>
#include <ManifestGenerationAlgorithms.au3>
Opt("GUIOnEventMode", 1) ; Change to OnEvent mode
;==============================================
;
;Draw GUI and declare variables
;
;==============================================
local $windowHeight = 500
local $windowWidth = 400
local $windowTitle = "Autopsy AutoIngest Manifest File Generator"
Global $hMainGUI = GUICreate($windowTitle, $windowWidth, $windowHeight) ;To make GUI resize add following args -1, -1, $WS_OVERLAPPEDWINDOW)
;GUICtrlSetResizing ($hMainGUI, $GUI_DOCKBORDERS)
GUISetOnEvent($GUI_EVENT_CLOSE, "CLOSEButton")
Global $propertiesFile = "ManifestTool.settings"
Global $workingDir = @WorkingDir
local $topMargin = 12
local $leftMargin = 12
local $labelOffset = 1
local $buttonOffset = -3
local $progressAreaInset = 8
local $distanceFromTop = $topMargin
local $distanceFromLeft = $leftMargin
Global $defaultDirectory = @MyDocumentsDir & "\"
local $labelWidth = 58
local $fieldWidth = 235
local $buttonWidth = 60
local $fieldHeight = 20
local $progressAreaWidth = $windowWidth - 2*($progressAreaInset+$leftMargin)
local $gapBetweenWidth = 10
local $gapBetweenHeight = 10
;Draw the GUI Code
GUICtrlCreateLabel("Algorithm", $distanceFromLeft, $distanceFromTop+$labelOffset)
$distanceFromLeft = $distanceFromLeft+$labelWidth+$gapBetweenWidth
Global $algorithmComboBox = GUICtrlCreateCombo(GetDefaultAlgorithmName(), $distanceFromLeft, $distanceFromTop, $fieldWidth, $fieldHeight, $CBS_DROPDOWNLIST)
GUICtrlSetOnEvent($algorithmComboBox, "Redraw")
Global $allAlgorithmNames = GetAlgorithmNames()
for $algorithmName IN $allAlgorithmNames
; Add additional items to the combobox.
GUICtrlSetData($algorithmComboBox, $algorithmName)
Next
$distanceFromLeft = $leftMargin
$distanceFromTop = $distanceFromTop + $fieldHeight + $gapBetweenHeight
Global $rootFolderLabel = GUICtrlCreateLabel("Root Folder", $distanceFromLeft, $distanceFromTop+$labelOffset)
$distanceFromLeft = $distanceFromLeft+$labelWidth+$gapBetweenWidth
Global $rootFolderField = GUICtrlCreateInput("", $distanceFromLeft, $distanceFromTop, $fieldWidth, $fieldHeight)
$distanceFromLeft = $distanceFromLeft +$fieldWidth+$gapBetweenWidth
Global $browseButton = GUICtrlCreateButton("Browse", $distanceFromLeft, $distanceFromTop+$buttonOffset, $buttonWidth)
$distanceFromLeft = $leftMargin
$distanceFromTop = $distanceFromTop + $fieldHeight + $gapBetweenHeight
Global $caseNameLabel = GUICtrlCreateLabel("Case Name", $distanceFromLeft, $distanceFromTop+$labelOffset)
$distanceFromLeft = $distanceFromLeft+$labelWidth+$gapBetweenWidth
Global $caseNameField = GUICtrlCreateInput("", $distanceFromLeft, $distanceFromTop, $fieldWidth, $fieldHeight)
$distanceFromLeft = $leftMargin
$distanceFromTop = $distanceFromTop + $fieldHeight + $gapBetweenHeight
$distanceFromTop = $distanceFromTop + $gapBetweenHeight ;add an extra gap before run button
Global $runButton = GUICtrlCreateButton("Run", $distanceFromLeft, $distanceFromTop+$buttonOffset, $buttonWidth)
GUICtrlSetOnEvent($runButton, "AlgorithmRunAction")
$distanceFromTop = $distanceFromTop + $fieldHeight + $gapBetweenHeight
$distanceFromTop = $distanceFromTop + $fieldHeight + $gapBetweenHeight ;add extra gap before progress area
local $ProgressLabel = GUICtrlCreateLabel("Progress", $distanceFromLeft, $distanceFromTop+$labelOffset)
$distanceFromTop = $distanceFromTop + $fieldHeight + $gapBetweenHeight
$distanceFromLeft = $distanceFromLeft + $progressAreaInset
$progressAreaHeight = $windowHeight -$distanceFromTop - $gapBetweenHeight - $gapBetweenHeight - $fieldHeight ;calculate height of progress area to use remaining space minus space for exit button
Global $progressField = GUICtrlCreateEdit("", $distanceFromLeft, $distanceFromTop, $progressAreaWidth, $progressAreaHeight, BitOr($ES_READONLY,$WS_VSCROLL, $ES_MULTILINE))
$distanceFromLeft = $distanceFromLeft + $progressAreaWidth - $buttonWidth
$distanceFromTop = $distanceFromTop + $progressAreaHeight + $gapBetweenHeight
Local $exitButton = GUICtrlCreateButton("Exit", $distanceFromLeft, $distanceFromTop+$buttonOffset, $buttonWidth)
GUICtrlSetOnEvent($exitButton, "CLOSEButton")
GUISetOnEvent($GUI_EVENT_CLOSE, "CLOSEButton")
GUISwitch($hMainGUI)
GUISetState(@SW_SHOW)
ChangeToDefaultGUI()
ReadPropertiesFile()
Local $oldCaseName = GUICtrlRead($caseNameField)
local $oldRootFolder = GUICtrlRead($rootFolderField)
While 1
Sleep(100) ; Sleep to reduce CPU usage
ValidateFields($oldCaseName, $oldRootFolder) ;validate here so that we check the current value of any input areas without requiring a change in focus
$oldCaseName = GUICtrlRead($caseNameField)
$oldRootFolder = GUICtrlRead($rootFolderField)
WEnd
;==============================================
;
;Functions
;
;==============================================
; Read the saved properties file, if none exist make one with the current settings
Func ReadPropertiesFile()
If FileExists($propertiesFile) <> 1 Then
FileChangeDir($workingDir)
_FileCreate($propertiesFile)
WritePropertiesFile()
Endif
Local $propertiesFileHandle = FileOpen($propertiesFile, $FO_READ)
Local $savedSelection = FileReadLine($propertiesFileHandle, 1)
Local $indexOfSelection = _ArraySearch($allAlgorithmNames, $savedSelection)
if ($indexOfSelection >= 0) Then
GUICtrlSetData($algorithmComboBox, $savedSelection, $savedSelection)
EndIf
Local $savedDirectory = FileReadLine($propertiesFileHandle, 2)
if (FileExists($savedDirectory)) Then
$defaultDirectory = $savedDirectory
EndIf
FileClose($propertiesFileHandle)
Redraw()
EndFunc
; Write the current settings to the properties file
Func WritePropertiesFile()
FileChangeDir($workingDir)
Local $propertiesFileHandle = FileOpen($propertiesFile, $FO_OVERWRITE)
If $propertiesFileHandle == -1 Then ;can't access the properties file so exit
Return
EndIf
FileWrite($propertiesFileHandle, GUICtrlRead($algorithmComboBox) & @CRLF)
FileWrite($propertiesFileHandle, $defaultDirectory & @CRLF)
FileClose($propertiesFileHandle)
EndFunc
;Make only the settings and labels relevent to the selected Algorithm visible using $GUI_SHOW and $GUI_HIDE
Func Redraw()
; Note: At this point @GUI_CtrlId would equal algorithmComboBox
Local $selectedAlgName = GUICtrlRead($algorithmComboBox)
;Move controls based on what is hidden or shown using ControlGetPos() and GUICtrlSetPos()
If $selectedAlgName == $allAlgorithmNames[2] Then ;"One Data Source Per Folder"
ChangeToDefaultGUI()
ElseIf $selectedAlgName == $allAlgorithmNames[0] Then ;"Single Data Source"
ChangeToSingleDataSourceGUI()
ElseIf $selectedAlgName == $allAlgorithmNames[1] Then ;"Folder of Logical Files"
ChangeToFolderOfLogicalFilesGUI()
EndIf
EndFunc ;==>AlgorithmComboBox
;Change the controls displayed in the GUI to the ones needed for the Single Data Source algorithm
Func ChangeToSingleDataSourceGUI()
ClearFields()
GUICtrlSetData($rootFolderLabel, "Data Source")
GUICtrlSetState($caseNameField, $GUI_SHOW)
GUICtrlSetState($caseNameLabel, $GUI_SHOW)
GUICtrlSetOnEvent($browseButton, "BrowseForDataSourceFile")
GUICtrlSetState($runButton, $GUI_DISABLE)
EndFunc
;Change the controls displayed in the GUI to the ones needed for the Folder of Logical Files algorithm
Func ChangeToFolderOfLogicalFilesGUI()
ClearFields()
GUICtrlSetData($rootFolderLabel, "Data Source")
GUICtrlSetData($rootFolderLabel, "Data Source")
GUICtrlSetState($caseNameField, $GUI_SHOW)
GUICtrlSetState($caseNameLabel, $GUI_SHOW)
GUICtrlSetOnEvent($browseButton, "Browse")
GUICtrlSetState($runButton, $GUI_DISABLE)
EndFunc
;Change the controls displayed in the GUI to the ones needed for One
Func ChangeToDefaultGUI()
ClearFields()
GUICtrlSetData($rootFolderLabel, "Root Folder")
GUICtrlSetState($rootFolderField, $GUI_SHOW)
GUICtrlSetState($rootFolderLabel, $GUI_SHOW)
GUICtrlSetState($caseNameField, $GUI_HIDE)
GUICtrlSetState($caseNameLabel, $GUI_HIDE)
GUICtrlSetOnEvent($browseButton, "Browse")
;rename to RootDirectory to root directory
;hide case name field
GUICtrlSetState($runButton, $GUI_DISABLE)
EndFunc
;ensure that all fields for the selected algorithm are valid
Func ValidateFields($oldCaseName, $oldRootFolder)
Local $dataSourcePath = GUICtrlRead($rootFolderField)
Local $caseName = GUICtrlRead($caseNameField)
if ($dataSourcePath <> $oldRootFolder Or $caseName <> $oldCaseName) Then
Local $selectedAlgName = GUICtrlRead($algorithmComboBox)
If $selectedAlgName == $allAlgorithmNames[2] Then ;"One Data Source Per Folder"
ValidateDefaultFields($dataSourcePath)
ElseIf $selectedAlgName == $allAlgorithmNames[0] Then ;"Single Data Source"
ValidateSingleDataSourceFields($dataSourcePath, $caseName)
ElseIf $selectedAlgName == $allAlgorithmNames[1] Then ;"Folder of Logical Files"
ValidateSingleDataSourceFields($dataSourcePath, $caseName)
EndIf
EndIf
EndFunc
;ensure that the settings for the default algorithm are valid before enabling it
Func ValidateDefaultFields($rootFolderPath)
if ($rootFolderPath <> "" And FileExists($rootFolderPath)) Then
GUICtrlSetState($runButton, $GUI_ENABLE)
Else
GUICtrlSetState($runButton, $GUI_DISABLE)
EndIf
EndFunc
;ensure that the settings for the Single Data Source and Folder of Logical Files algorithms are valid
Func ValidateSingleDataSourceFields($dataSourcePath, $caseName)
if ($dataSourcePath <> "" And FileExists($dataSourcePath) And $caseName <> "") Then
GUICtrlSetState($runButton, $GUI_ENABLE)
Else
GUICtrlSetState($runButton, $GUI_DISABLE)
EndIf
EndFunc
;clear all input fields, and reset them to an empty string
Func ClearFields()
GUICtrlSetData($rootFolderField, "")
GUICtrlSetData($caseNameField, "")
EndFunc
;Open a directory chooser
Func Browse()
; Note: At this point @GUI_CtrlId would equal $browseButton
GUICtrlSetState($browseButton, $GUI_DISABLE)
Local $selectedDirectory = FileSelectFolder("Select Folder", $defaultDirectory)
Local $caseDir = ""
Local $caseDrive = ""
If (FileExists($selectedDirectory)) Then
_PathSplit($selectedDirectory, $caseDrive, $caseDir, "", "")
$defaultDirectory = $caseDrive & $caseDir
GUICtrlSetData($rootFolderField, $selectedDirectory)
EndIf
GUICtrlSetState($caseNameField, $GUI_FOCUS)
GUICtrlSetState($browseButton, $GUI_ENABLE)
EndFunc ;==>BrowseButton
; Open a file chooser
Func BrowseForDataSourceFile()
; Note: At this point @GUI_CtrlId would equal $browseButton
GUICtrlSetState($browseButton, $GUI_DISABLE)
Local $selectedDataSource = FileOpenDialog("Select Data Source", $defaultDirectory, "All Supported Types (*.img; *.dd; *.001; *.aa; *.raw; *.bin; *.E01; *.vmdk; *.vhd) |Raw Images (*.img; *.dd; *.001; *.aa; *.raw; *.bin) |Encase Images (*.E01) |Virtual Machines (*.vmdk; *.vhd) |Logical Evidence File (*.L01) |All Files (*.*)", $FD_FILEMUSTEXIST)
Local $caseDir = ""
Local $caseDrive = ""
If (FileExists($selectedDataSource)) Then
_PathSplit ($selectedDataSource, $caseDrive, $caseDir, "", "")
$defaultDirectory = $caseDrive & $caseDir
GUICtrlSetData($rootFolderField, $selectedDataSource)
EndIf
GUICtrlSetState($caseNameField, $GUI_FOCUS)
GUICtrlSetState($browseButton, $GUI_ENABLE)
EndFunc
;Perform the action associated with the run button which should be defined in ManifestGenerationAlgorithms.au3
Func AlgorithmRunAction()
; Note: At this point @GUI_CtrlId would equal $runButton
GUICtrlSetState($runButton, $GUI_DISABLE)
RunAlgorithm(GUICtrlRead($algorithmComboBox), GetSettings(), $progressField)
GUICtrlSetState($runButton, $GUI_ENABLE)
EndFunc ;==>RunButton
;Get an array of settings as they are set on this panel
Func GetSettings()
Local $settings[2]
$settings[0] = GUICtrlRead($rootFolderField)
$settings[1] = GUICtrlRead($caseNameField)
Return $settings
EndFunc
;Close the tool
Func CLOSEButton()
; Note: at this point @GUI_CtrlId would equal $GUI_EVENT_CLOSE,
; @GUI_WinHandle will be either $hMainGUI or $hDummyGUI
GUICtrlSetState($exitButton, $GUI_DISABLE)
If @GUI_WinHandle = $hMainGUI Then
Local $msgBoxAnswer = MsgBox(1, "Close Tool Confirmation", "Press OK to confirm closing the tool")
if $msgBoxAnswer == 1 Then
WritePropertiesFile()
Exit
EndIf
EndIf
GUICtrlSetState($exitButton, $GUI_ENABLE)
EndFunc ;==>CLOSEButton

Binary file not shown.

View File

@ -2,7 +2,6 @@ cannotBuildXmlParser=Unable to build XML parser:
cannotLoadSEUQA=Unable to load Search Engine URL Query Analyzer settings file, SEUQAMappings.xml:
cannotParseXml=Unable to parse XML file:
ChromeCacheExtractor.moduleName=ChromeCacheExtractor
# {0} - OS name
DataSourceUsageAnalyzer.customVolume.label=OS Drive ({0})
DataSourceUsageAnalyzer.parentModuleName=Recent Activity
Extract.indexError.message=Failed to index artifact for keyword search.
@ -48,8 +47,16 @@ ExtractSafari_Error_Getting_History=An error occurred while processing Safari hi
ExtractSafari_Error_Parsing_Bookmark=An error occured while processing Safari Bookmark files
ExtractSafari_Error_Parsing_Cookies=An error occured while processing Safari Cookies files
ExtractSafari_Module_Name=Safari
ExtractZone_Internet=Internet Zone
ExtractZone_Local_Intranet=Local Intranet Zone
ExtractZone_Local_Machine=Local Machine Zone
ExtractZone_process_errMsg=An error occured processing ':Zone.Indentifier' files.
ExtractZone_process_errMsg_find=A failure occured while searching for :Zone.Indentifier files.
ExtractZone_progress_Msg=Extracting :Zone.Identifer files
ExtractZone_Restricted=Restricted Sites Zone
ExtractZone_Trusted=Trusted Sites Zone
OpenIDE-Module-Display-Category=Ingest Module
OpenIDE-Module-Long-Description=Recent Activity ingest module.\n\n\The module extracts useful information about the recent user activity on the disk image being ingested, such as:\n\n- Recently open documents,\n- Web acitivity (sites visited, stored cookies, bookmarked sites, search engine queries, file downloads),\n- Recently attached devices,\n- Installed programs.\n\n\The module currently supports Windows only disk images.\n\The plugin is also fully functional when deployed on Windows version of Autopsy.
OpenIDE-Module-Long-Description=Recent Activity ingest module.\n\nThe module extracts useful information about the recent user activity on the disk image being ingested, such as:\n\n- Recently open documents,\n- Web acitivity (sites visited, stored cookies, bookmarked sites, search engine queries, file downloads),\n- Recently attached devices,\n- Installed programs.\n\nThe module currently supports Windows only disk images.\nThe plugin is also fully functional when deployed on Windows version of Autopsy.
OpenIDE-Module-Name=RecentActivity
OpenIDE-Module-Short-Description=Recent Activity finder ingest module
Chrome.moduleName=Chrome
@ -173,12 +180,11 @@ RecentDocumentsByLnk.parentModuleName.noSpace=RecentActivity
RecentDocumentsByLnk.parentModuleName=Recent Activity
RegRipperFullNotFound=Full version RegRipper executable not found.
RegRipperNotFound=Autopsy RegRipper executable not found.
# {0} - file name
SearchEngineURLQueryAnalyzer.init.exception.msg=Unable to find {0}.
SearchEngineURLQueryAnalyzer.moduleName.text=Search Engine
SearchEngineURLQueryAnalyzer.engineName.none=NONE
SearchEngineURLQueryAnalyzer.domainSubStr.none=NONE
SearchEngineURLQueryAnalyzer.toString=Name: {0}\nDomain Substring: {1}\n\count: {2}\nSplit Tokens: \n{3}
SearchEngineURLQueryAnalyzer.toString=Name: {0}\nDomain Substring: {1}\ncount: {2}\nSplit Tokens: \n{3}
SearchEngineURLQueryAnalyzer.parentModuleName.noSpace=RecentActivity
SearchEngineURLQueryAnalyzer.parentModuleName=Recent Activity
UsbDeviceIdMapper.parseAndLookup.text=Product: {0}

View File

@ -37,6 +37,7 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import org.apache.commons.io.FilenameUtils;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
@ -514,12 +515,13 @@ class Chrome extends Extract {
tempList = this.dbConnect(temps, DOWNLOAD_QUERY_V30);
}
logger.log(Level.INFO, "{0}- Now getting downloads from {1} with {2}artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS
logger.log(Level.INFO, "{0}- Now getting downloads from {1} with {2} artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS
for (HashMap<String, Object> result : tempList) {
Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
String fullPath = result.get("full_path").toString(); //NON-NLS
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH,
RecentActivityExtracterModuleFactory.getModuleName(), (result.get("full_path").toString()))); //NON-NLS
long pathID = Util.findID(dataSource, (result.get("full_path").toString())); //NON-NLS
RecentActivityExtracterModuleFactory.getModuleName(), fullPath));
long pathID = Util.findID(dataSource, fullPath);
if (pathID != -1) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH_ID,
NbBundle.getMessage(this.getClass(),
@ -546,6 +548,19 @@ class Chrome extends Extract {
if (bbart != null) {
bbartifacts.add(bbart);
}
// find the downloaded file and create a TSK_DOWNLOAD_SOURCE for it..
try {
for (AbstractFile downloadedFile : fileManager.findFiles(dataSource, FilenameUtils.getName(fullPath), FilenameUtils.getPath(fullPath))) {
BlackboardArtifact downloadSourceArt = downloadedFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE);
downloadSourceArt.addAttributes(createDownloadSourceAttributes(result.get("url").toString()));
bbartifacts.add(downloadSourceArt);
break;
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, String.format("Error creating download source artifact for file '%s'", fullPath), ex); //NON-NLS
}
}
dbFile.delete();

View File

@ -379,7 +379,7 @@ abstract class Extract {
* @param accessTime Time the download occurred
* @param domain Domain of the URL
* @param programName Name of the module creating the attribute
* @return A collection of attributed of a downloaded file
* @return A collection of attributes of a downloaded file
*/
protected Collection<BlackboardAttribute> createDownloadAttributes(String path, Long pathID, String url, Long accessTime, String domain, String programName) {
Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
@ -414,6 +414,22 @@ abstract class Extract {
return bbattributes;
}
/**
* Creates a list of the attributes for source of a downloaded file
*
* @param url source URL of the downloaded file
* @return A collection of attributes for source of a downloaded file
*/
protected Collection<BlackboardAttribute> createDownloadSourceAttributes(String url) {
Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
bbattributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL,
RecentActivityExtracterModuleFactory.getModuleName(),
(url != null) ? url : "")); //NON-NLS
return bbattributes;
}
/**
* Create temporary file for the given AbstractFile. The new file will be
* created in the temp directory for the module with a unique file name.

View File

@ -36,6 +36,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.io.FilenameUtils;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.services.FileManager;
import org.sleuthkit.autopsy.coreutils.Logger;
@ -48,6 +49,7 @@ import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.autopsy.recentactivity.BinaryCookieReader.Cookie;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException;
import org.xml.sax.SAXException;
@ -503,7 +505,7 @@ final class ExtractSafari extends Extract {
for(NSObject obj: objectArray){
if(obj instanceof NSDictionary){
bbartifacts.add(parseDownloadDictionary(dataSource, origFile, (NSDictionary)obj));
bbartifacts.addAll(parseDownloadDictionary(dataSource, origFile, (NSDictionary)obj));
}
}
break;
@ -612,12 +614,15 @@ final class ExtractSafari extends Extract {
* @return a Blackboard Artifact for the download.
* @throws TskCoreException
*/
private BlackboardArtifact parseDownloadDictionary(Content dataSource, AbstractFile origFile, NSDictionary entry) throws TskCoreException {
private Collection<BlackboardArtifact> parseDownloadDictionary(Content dataSource, AbstractFile origFile, NSDictionary entry) throws TskCoreException {
Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
String url = null;
String path = null;
Long time = null;
Long pathID = null;
FileManager fileManager = getCurrentCase().getServices().getFileManager();
NSString nsstring = (NSString) entry.get(PLIST_KEY_DOWNLOAD_URL);
if (nsstring != null) {
url = nsstring.toString();
@ -636,7 +641,16 @@ final class ExtractSafari extends Extract {
BlackboardArtifact bbart = origFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD);
bbart.addAttributes(this.createDownloadAttributes(path, pathID, url, time, NetworkUtils.extractDomain(url), getName()));
return bbart;
bbartifacts.add(bbart);
// find the downloaded file and create a TSK_DOWNLOAD_SOURCE for it.
for (AbstractFile downloadedFile : fileManager.findFiles(dataSource, FilenameUtils.getName(path), FilenameUtils.getPath(path))) {
BlackboardArtifact downloadSourceArt = downloadedFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE);
downloadSourceArt.addAttributes(createDownloadSourceAttributes(url));
bbartifacts.add(downloadSourceArt);
break;
}
return bbartifacts;
}
}

View File

@ -0,0 +1,388 @@
/*
*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
*
* 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.recentactivity;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Level;
import org.apache.commons.lang3.StringUtils;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.NetworkUtils;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress;
import org.sleuthkit.autopsy.ingest.IngestJobContext;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD;
import org.sleuthkit.datamodel.BlackboardAttribute;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ReadContentInputStream;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Extract the <i>:Zone.Indentifier<i> alternate data stream files. A file with
* a <i>:Zone.Indentifier<i> extention contains information about the similarly
* named (with out zone identifer extension) downloaded file.
*/
final class ExtractZoneIdentifier extends Extract {
private static final Logger LOG = Logger.getLogger(ExtractEdge.class.getName());
private static final String ZONE_IDENTIFIER_FILE = "%:Zone.Identifier"; //NON-NLS
private static final String ZONE_IDENTIFIER = ":Zone.Identifier"; //NON-NLS
@Messages({
"ExtractZone_process_errMsg_find=A failure occured while searching for :Zone.Indentifier files.",
"ExtractZone_process_errMsg=An error occured processing ':Zone.Indentifier' files.",
"ExtractZone_progress_Msg=Extracting :Zone.Identifer files"
})
@Override
void process(Content dataSource, IngestJobContext context, DataSourceIngestModuleProgress progressBar) {
progressBar.progress(Bundle.ExtractZone_progress_Msg());
List<AbstractFile> zoneFiles = null;
try {
zoneFiles = currentCase.getServices().getFileManager().findFiles(dataSource, ZONE_IDENTIFIER_FILE);
} catch (TskCoreException ex) {
addErrorMessage(Bundle.ExtractZone_process_errMsg_find());
LOG.log(Level.SEVERE, "Unable to find zone identifier files, exception thrown. ", ex); // NON-NLS
}
if (zoneFiles == null || zoneFiles.isEmpty()) {
return;
}
Set<Long> knownPathIDs = null;
try {
knownPathIDs = getPathIDsForType(TSK_WEB_DOWNLOAD);
} catch (TskCoreException ex) {
addErrorMessage(Bundle.ExtractZone_process_errMsg());
LOG.log(Level.SEVERE, "Failed to build PathIDs List for TSK_WEB_DOWNLOAD", ex); // NON-NLS
}
if (knownPathIDs == null) {
return;
}
Collection<BlackboardArtifact> sourceArtifacts = new ArrayList<>();
Collection<BlackboardArtifact> downloadArtifacts = new ArrayList<>();
for (AbstractFile zoneFile : zoneFiles) {
try {
processZoneFile(context, dataSource, zoneFile, sourceArtifacts, downloadArtifacts, knownPathIDs);
} catch (TskCoreException ex) {
addErrorMessage(Bundle.ExtractZone_process_errMsg());
String message = String.format("Failed to process zone identifier file %s", zoneFile.getName()); //NON-NLS
LOG.log(Level.WARNING, message, ex);
}
}
IngestServices services = IngestServices.getInstance();
if (!sourceArtifacts.isEmpty()) {
services.fireModuleDataEvent(new ModuleDataEvent(
RecentActivityExtracterModuleFactory.getModuleName(),
TSK_DOWNLOAD_SOURCE, sourceArtifacts));
}
if (!downloadArtifacts.isEmpty()) {
services.fireModuleDataEvent(new ModuleDataEvent(
RecentActivityExtracterModuleFactory.getModuleName(),
TSK_WEB_DOWNLOAD, downloadArtifacts));
}
}
/**
* Process a single Zone Identifier file.
*
* @param context IngetJobContext
* @param dataSource Content
* @param zoneFile Zone Indentifier file
* @param sourceArtifacts List for TSK_DOWNLOAD_SOURCE artifacts
* @param downloadArtifacts List for TSK_WEB_DOWNLOAD aritfacts
*
* @throws TskCoreException
*/
private void processZoneFile(IngestJobContext context, Content dataSource,
AbstractFile zoneFile, Collection<BlackboardArtifact> sourceArtifacts,
Collection<BlackboardArtifact> downloadArtifacts,
Set<Long> knownPathIDs) throws TskCoreException {
ZoneIdentifierInfo zoneInfo = null;
try {
zoneInfo = new ZoneIdentifierInfo(zoneFile);
} catch (IOException ex) {
String message = String.format("Unable to parse temporary File for %s", zoneFile.getName()); //NON-NLS
LOG.log(Level.WARNING, message, ex);
}
if (zoneInfo == null) {
return;
}
AbstractFile downloadFile = getDownloadFile(dataSource, zoneFile);
if (downloadFile != null) {
// Only create a new TSK_WEB_DOWNLOAD artifact if one does not exist for downloadFile
if (!knownPathIDs.contains(downloadFile.getDataSourceObjectId())) {
// The zone identifier file is the parent of this artifact
// because it is the file we parsed to get the data
BlackboardArtifact downloadBba = createDownloadArtifact(zoneFile, zoneInfo);
if (downloadBba != null) {
downloadArtifacts.add(downloadBba);
}
}
// check if download has a child TSK_DOWNLOAD_SOURCE artifact, if not create one
if (downloadFile.getArtifactsCount(TSK_DOWNLOAD_SOURCE) == 0) {
BlackboardArtifact sourceBba = createDownloadSourceArtifact(downloadFile, zoneInfo);
if (sourceBba != null) {
sourceArtifacts.add(sourceBba);
}
}
}
}
/**
* Find the file that the Zone.Identifer file was created alongside.
*
* @param dataSource Content
* @param zoneFile The zone identifier case file
*
* @return The downloaded file or null if a file was not found
*
* @throws TskCoreException
*/
private AbstractFile getDownloadFile(Content dataSource, AbstractFile zoneFile) throws TskCoreException {
AbstractFile downloadFile = null;
org.sleuthkit.autopsy.casemodule.services.FileManager fileManager
= currentCase.getServices().getFileManager();
String downloadFileName = zoneFile.getName().replace(ZONE_IDENTIFIER, ""); //NON-NLS
List<AbstractFile> fileList = fileManager.findFiles(dataSource, downloadFileName, zoneFile.getParentPath());
if (fileList.size() == 1) {
downloadFile = fileList.get(0);
// Check that the download file and the zone file came from the same dir
if (!downloadFile.getParentPath().equals(zoneFile.getParentPath())) {
downloadFile = null;
} else if (zoneFile.getMetaAddr() != downloadFile.getMetaAddr()) {
downloadFile = null;
}
}
return downloadFile;
}
/**
* Create a Download Source Artifact for the given ZoneIdentifierInfo
* object.
*
* @param downloadFile AbstractFile representing the file downloaded, not
* the zone indentifier file.
* @param zoneInfo Zone Indentifer file wrapper object
*
* @return TSK_DOWNLOAD_SOURCE object for given parameters
*/
private BlackboardArtifact createDownloadSourceArtifact(AbstractFile downloadFile, ZoneIdentifierInfo zoneInfo) {
Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
bbattributes.addAll(Arrays.asList(
new BlackboardAttribute(TSK_URL,
RecentActivityExtracterModuleFactory.getModuleName(),
StringUtils.defaultString(zoneInfo.getURL(), "")),
new BlackboardAttribute(TSK_DOMAIN,
RecentActivityExtracterModuleFactory.getModuleName(),
(zoneInfo.getURL() != null) ? NetworkUtils.extractDomain(zoneInfo.getURL()) : ""),
new BlackboardAttribute(TSK_LOCATION,
RecentActivityExtracterModuleFactory.getModuleName(),
StringUtils.defaultString(zoneInfo.getZoneIdAsString(), "")))); //NON-NLS
return addArtifact(TSK_DOWNLOAD_SOURCE, downloadFile, bbattributes);
}
/**
* Create a TSK_WEB_DOWNLOAD Artifact for the given zone indentifier file.
*
* @param zoneFile Zone identifier file
* @param zoneInfo ZoneIdentifierInfo file wrapper object
*
* @return BlackboardArifact for the given parameters
*/
private BlackboardArtifact createDownloadArtifact(AbstractFile zoneFile, ZoneIdentifierInfo zoneInfo) {
Collection<BlackboardAttribute> bbattributes = createDownloadAttributes(
null, null,
zoneInfo.getURL(), null,
(zoneInfo.getURL() != null ? NetworkUtils.extractDomain(zoneInfo.getURL()) : ""),
null);
return addArtifact(TSK_WEB_DOWNLOAD, zoneFile, bbattributes);
}
/**
* Creates a list of PathIDs for the given Artifact type.
*
* @param type BlackboardArtifact.ARTIFACT_TYPE
*
* @return A list of PathIDs
*
* @throws TskCoreException
*/
private Set<Long> getPathIDsForType(BlackboardArtifact.ARTIFACT_TYPE type) throws TskCoreException {
Set<Long> idList = new HashSet<>();
for (BlackboardArtifact artifact : currentCase.getSleuthkitCase().getBlackboardArtifacts(type)) {
BlackboardAttribute pathIDAttribute = artifact.getAttribute(new BlackboardAttribute.Type(TSK_PATH_ID));
if (pathIDAttribute != null) {
long contentID = pathIDAttribute.getValueLong();
if (contentID != -1) {
idList.add(contentID);
}
}
}
return idList;
}
@Messages({
"ExtractZone_Local_Machine=Local Machine Zone",
"ExtractZone_Local_Intranet=Local Intranet Zone",
"ExtractZone_Trusted=Trusted Sites Zone",
"ExtractZone_Internet=Internet Zone",
"ExtractZone_Restricted=Restricted Sites Zone"
})
/**
* Wrapper class for information in the :ZoneIdentifier file. The
* Zone.Identifier file has a simple format of <i>key<i>=<i>value<i>. There
* are four known keys: ZoneId, ReferrerUrl, HostUrl, and
* LastWriterPackageFamilyName. Not all browsers will put all values in the
* file, in fact most will only supply the ZoneId. Only Edge supplies the
* LastWriterPackageFamilyName.
*/
private final static class ZoneIdentifierInfo {
private static final String ZONE_ID = "ZoneId"; //NON-NLS
private static final String REFERRER_URL = "ReferrerUrl"; //NON-NLS
private static final String HOST_URL = "HostUrl"; //NON-NLS
private static final String FAMILY_NAME = "LastWriterPackageFamilyName"; //NON-NLS
private final Properties properties = new Properties(null);
/**
* Opens the zone file, reading for the key\value pairs and puts them
* into a HashMap.
*
* @param zoneFile The ZoneIdentifier file
*
* @throws FileNotFoundException
* @throws IOException
*/
ZoneIdentifierInfo(AbstractFile zoneFile) throws IOException {
properties.load(new ReadContentInputStream(zoneFile));
}
/**
* Get the integer zone id
*
* @return interger zone id or -1 if unknown
*/
private int getZoneId() {
int zoneValue = -1;
String value = properties.getProperty(ZONE_ID);
if (value != null) {
zoneValue = Integer.parseInt(value);
}
return zoneValue;
}
/**
* Get the string description of the zone id.
*
* @return String description or null if a zone id was not found
*/
private String getZoneIdAsString() {
switch (getZoneId()) {
case 0:
return Bundle.ExtractZone_Local_Machine();
case 1:
return Bundle.ExtractZone_Local_Intranet();
case 2:
return Bundle.ExtractZone_Trusted();
case 3:
return Bundle.ExtractZone_Internet();
case 4:
return Bundle.ExtractZone_Restricted();
default:
return null;
}
}
/**
* Get the URL from which the file was downloaded.
*
* @return String url or null if a host url was not found
*/
private String getURL() {
return properties.getProperty(HOST_URL);
}
/**
* Get the referrer url.
*
* @return String url or null if a host url was not found
*/
private String getReferrer() {
return properties.getProperty(REFERRER_URL);
}
/**
* Gets the string value for the key LastWriterPackageFamilyName.
*
* @return String value or null if the value was not found
*/
private String getFamilyName() {
return properties.getProperty(FAMILY_NAME);
}
}
}

View File

@ -42,6 +42,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import org.apache.commons.io.FilenameUtils;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
@ -499,14 +500,14 @@ class Firefox extends Extract {
(Long.valueOf(result.get("startTime").toString())))); //NON-NLS
String target = result.get("target").toString(); //NON-NLS
String downloadedFilePath = "";
if (target != null) {
try {
String decodedTarget = URLDecoder.decode(target.replaceAll("file:///", ""), "UTF-8"); //NON-NLS
downloadedFilePath = URLDecoder.decode(target.replaceAll("file:///", ""), "UTF-8"); //NON-NLS
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH,
RecentActivityExtracterModuleFactory.getModuleName(),
decodedTarget));
long pathID = Util.findID(dataSource, decodedTarget);
downloadedFilePath));
long pathID = Util.findID(dataSource, downloadedFilePath);
if (pathID != -1) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH_ID,
RecentActivityExtracterModuleFactory.getModuleName(),
@ -532,6 +533,19 @@ class Firefox extends Extract {
if (bbart != null) {
bbartifacts.add(bbart);
}
// find the downloaded file and create a TSK_DOWNLOAD_SOURCE for it.
try {
for (AbstractFile downloadedFile : fileManager.findFiles(dataSource, FilenameUtils.getName(downloadedFilePath), FilenameUtils.getPath(downloadedFilePath))) {
BlackboardArtifact downloadSourceArt = downloadedFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE);
downloadSourceArt.addAttributes(createDownloadSourceAttributes(source));
bbartifacts.add(downloadSourceArt);
break;
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, String.format("Error creating download source artifact for file '%s'",
downloadedFilePath), ex); //NON-NLS
}
}
if (errors > 0) {
this.addErrorMessage(
@ -619,13 +633,14 @@ class Firefox extends Extract {
//bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LAST_ACCESSED.getTypeID(), "RecentActivity", "Last Visited", (Long.valueOf(result.get("startTime").toString()))));
String target = result.get("target").toString(); //NON-NLS
String downloadedFilePath = "";
if (target != null) {
try {
String decodedTarget = URLDecoder.decode(target.replaceAll("file:///", ""), "UTF-8"); //NON-NLS
downloadedFilePath = URLDecoder.decode(target.replaceAll("file:///", ""), "UTF-8"); //NON-NLS
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH,
RecentActivityExtracterModuleFactory.getModuleName(),
decodedTarget));
long pathID = Util.findID(dataSource, decodedTarget);
downloadedFilePath));
long pathID = Util.findID(dataSource, downloadedFilePath);
if (pathID != -1) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH_ID,
RecentActivityExtracterModuleFactory.getModuleName(),
@ -652,6 +667,19 @@ class Firefox extends Extract {
if (bbart != null) {
bbartifacts.add(bbart);
}
// find the downloaded file and create a TSK_DOWNLOAD_SOURCE for it.
try {
for (AbstractFile downloadedFile : fileManager.findFiles(dataSource, FilenameUtils.getName(downloadedFilePath), FilenameUtils.getPath(downloadedFilePath))) {
BlackboardArtifact downloadSourceArt = downloadedFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE);
downloadSourceArt.addAttributes(createDownloadSourceAttributes(url));
bbartifacts.add(downloadSourceArt);
break;
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, String.format("Error creating download source artifact for file '%s'",
downloadedFilePath), ex); //NON-NLS
}
}
if (errors > 0) {
this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Firefox.getDlV24.errMsg.errParsingArtifacts",

View File

@ -76,6 +76,7 @@ public final class RAImageIngestModule implements DataSourceIngestModule {
Extract osExtract = new ExtractOs();
Extract dataSourceAnalyzer = new DataSourceUsageAnalyzer();
Extract safari = new ExtractSafari();
Extract zoneInfo = new ExtractZoneIdentifier();
extractors.add(chrome);
extractors.add(firefox);
@ -87,6 +88,7 @@ public final class RAImageIngestModule implements DataSourceIngestModule {
extractors.add(registry); // this should run after quicker modules like the browser modules and needs to run before the DataSourceUsageAnalyzer
extractors.add(osExtract); // this needs to run before the DataSourceUsageAnalyzer
extractors.add(dataSourceAnalyzer); //this needs to run after ExtractRegistry and ExtractOs
extractors.add(zoneInfo); // this needs to run after the web browser modules
browserExtractors.add(chrome);
browserExtractors.add(firefox);

View File

@ -102,6 +102,7 @@
<copy file="${basedir}/NEWS.txt" tofile="${zip-tmp}/${app.name}/NEWS.txt"/>
<copy file="${basedir}/Running_Linux_OSX.txt" tofile="${zip-tmp}/${app.name}/Running_Linux_OSX.txt"/>
<copy file="${basedir}/unix_setup.sh" tofile="${zip-tmp}/${app.name}/unix_setup.sh"/>
<copy file="${basedir}/ManifestTool/ManifestTool.exe" todir="${zip-tmp}/${app.name}/bin"/>
<copy file="${basedir}/icons/icon.ico" tofile="${zip-tmp}/${app.name}/icon.ico" overwrite="true"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 291 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

@ -0,0 +1,62 @@
/*! \page manifest_tool_page Manifest Tool
\section manifest_tool_overview Overview
Manifest Tool is an executable designed to assist in the automated creation of manifest files which are necessary to run Auto Ingest on a data source. There is no installation necessary. To use the tool double click on Manifest Tool executable, when it opens select the option with the algorithm you wish to run from the combo box, and fill in all the available settings before clicking the Run button. A log with the success or failure of each manifest file it attempts to create will appear in the progress area.
\section manifest_tool_output Output
The output of the Manifest Tool will be XML files ending in _Manifest.xml.
\subsection manifest_tool_one_ds_per_folder One Data Source Per Folder
The One Data Source Per Folder algorithm is designed for a specific use case when the case folder contains multiple subfolders, with each generally containing one data data source of a short list of types. Please see \ref manifest_tool_algorithm_specifics for details on this algorithm.
To use this algorithm, use the Browse button to select a root folder as the case directory. Then select the Run button to generate manifest files for each of the data sources detected. A manifest file will be generated for each subfolder of the selected root folder, the manifest files will be placed inside the selected root folder.
\subsection manifest_tool_single_ds Single Data Source
The Single Data Source algorithm is for creating a manifest file for a single image or logical file with a user specified case name.
To use this algorithm, use the Browse button to select a file to use as your data source, and enter a case name in the case name field. Then select the Run button to generate a manifest file. The manifest file will be created in the same folder as your selected data source.
\subsection manifest_tool_logical_file_folder Folder of Logical Files
The Folder of Logical Files algorithm is for creating a single manifest file for an entire folder of files which will all be ingested as logical files.
To use this algorithm, use the Browse button to select a folder to add as a folder of logical files, and enter a case name in the case name field. Then select the Run button to generate a manifest file. The manifest file will be created in the parent folder of your selected folder of logical files.
\section manifest_tol_example Example
Given a root folder that looks like this:
\image html AutoIngest/manifest_tool_root_folder.png
A user having selected the One Data Source Per Folder algorithm will get output that looks like the following, where a manifest now exists for each non-empty subfolder. The root folder's name will be used as the case name in the manifest files (in this example the case name will be TestCaseFolder.)
\image html AutoIngest/manifest_tool_ui.png
The contents of an XML file will have the following format:
\verbatim
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<AutopsyManifest>
<CaseName>TestCaseFolder</CaseName>
<DataSource>interestingL01\interesting_files2.L01</DataSource>
</AutopsyManifest>
\endverbatim
\section manifest_tool_algorithm_specifics One Data Source Per Folder Algorithm Specifics
<ul>
<li>The only configuration setting the user needs to choose is a root folder.
<li>The name of the specified root folder will become the case name used in the manifest files.
<li>Each non-empty subfolder in the root folder will have a manifest file created for it.
<li>All manifest files will be created in the root folder.
<li>Files directly in the root folder will be ignored and remain unprocessed.
<li>Subfolders which contain an .E01, .L01, .001, or .AD1 file, will have the first file of this type used as the data source in the manifest file.
<li>Subfolders which have more than one .E01, .L01, .001, or .AD1 file will have the additional files ignored and they will remain unprocessed.
<li>Subfolders without an .E01, .L01, .001, or .AD1 file will have the entire subfolder added as the data source.
<li>If the root folder already contains a specific _Manifest.xml file then it will not be replaced or modified.
</ul>
*/

View File

@ -0,0 +1,48 @@
/*! \page portable_case_page Portable Cases
\section portable_case_overview Overview
A portable case is a partial copy of a normal Autopsy case that can be opened from anywhere. The general use case is as follows:
<ol>
<li>Alice is analyzing one or more data sources using Autopsy. She tags files and results that are of particular interest.
<li>Alice wants to share her findings with Bob but is unable to send him the original data sources.
<li>Alice creates a portable case which will contain only her tagged files and results, plus any files associated with those results, and sends it to Bob.
<li>Bob can open the portable case in Autopsy and view all files and results Alice tagged, and run any of the normal Autopsy features.
</ol>
For example, Alice's original case could look like this:
\image html portable_case_original_version.png
The portable version could like this:
\image html portable_case_portable_version.png
Alice only tagged eight files and results, so most of the original content is no longer in the case. Some of the data sources had no tagged items so they're not included at all. The file structure of any tagged files is preserved - you can see that the tagged image in the screenshot is still in the same location, but the non-tagged files are gone. Note that although the original images (such as "image1.vhd") appear in the tree, their contents are not included in the portable case.
\section portable_case_creation Creating a Portable Case
First you'll want to make sure that all the files and results you want included in the portable case are tagged - see the \ref tagging_page page for more details.
You can see what tags you've added in the \ref tree_viewer_page.
\image html portable_case_tags.png
Portable cases are created through the \ref reporting_page feature. The Generate Report dialog will display a list of all tags that are in use in the current case and you can choose which ones you would like to include. At the bottom you can select the output folder for the new case. By default it will be placed in the "Reports" folder in the current case.
\image html portable_case_report_panel.png
Here you can see the new portable case. It will be named with the original case name plus "(Portable)". The portable case is initially missing many of the normal Autopsy folders - these will be created the first time a user opens it. The portable case folder can be zipped and sent to a different user.
\image html portable_case_folder.png
\section portable_case_usage Using a Portable Case
Portable cases generally behave like any other Autopsy case. You can run ingest, do keyword searches, use the timeline viewer, etc. One point to note is that while the original data source names appear in the case, the data sources themselves were not copied into the portable case.
\image html portable_case_empty_image.png
This may cause warning or error messages when using ingest modules that run on the full image, such as the \ref data_source_integrity_page. You will also not be able to view the data sources in the content viewer.
You can also add additonal data sources to the portable case if you wish. The case will no longer be portable, but if desired you could generate a new portable case that will include tagged files and results from the new data sources as well as the original case.
*/

View File

@ -82,6 +82,10 @@ This report module generates a KML file from any GPS data in the case. This file
\image html reports_kml.png
\subsection report_portable_case Portable Case
This report module generates a new Autopsy case from any tagged files and results. See the \ref portable_case_page page for additional information.
\subsection report_stix STIX
The STIX module allows you to generate a report and Interesting File artifacts by running a STIX file (or files) against the data sources in the case.