removing unneeded classes

This commit is contained in:
Greg DiCristofaro 2022-03-29 15:36:35 -04:00
parent 441a9c6f23
commit 721fc11c48
37 changed files with 65 additions and 3930 deletions

View File

@ -29,7 +29,6 @@ import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.datamodel.Reports;
import org.sleuthkit.datamodel.Report;
import org.sleuthkit.datamodel.TskCoreException;
@ -64,19 +63,23 @@ public class DeleteReportAction extends AbstractAction {
@NbBundle.Messages({
"DeleteReportAction.showConfirmDialog.single.explanation=The report will remain on disk.",
"DeleteReportAction.showConfirmDialog.multiple.explanation=The reports will remain on disk.",
"DeleteReportAction.showConfirmDialog.errorMsg=An error occurred while deleting the reports."})
"DeleteReportAction.showConfirmDialog.errorMsg=An error occurred while deleting the reports.",
"DeleteReportAction.actionPerformed.showConfirmDialog.title=Confirm Deletion",
"DeleteReportAction.actionPerformed.showConfirmDialog.single.msg=Do you want to delete 1 report from the case?",
"# {0} - reportNum",
"DeleteReportAction.actionPerformed.showConfirmDialog.multiple.msg=Do you want to delete {0} reports from the case?"})
@Override
public void actionPerformed(ActionEvent e) {
Collection<? extends Report> selectedReportsCollection = Utilities.actionsGlobalContext().lookupAll(Report.class);
String message = selectedReportsCollection.size() > 1
? NbBundle.getMessage(Reports.class, "DeleteReportAction.actionPerformed.showConfirmDialog.multiple.msg", selectedReportsCollection.size())
: NbBundle.getMessage(Reports.class, "DeleteReportAction.actionPerformed.showConfirmDialog.single.msg");
? Bundle.DeleteReportAction_actionPerformed_showConfirmDialog_multiple_msg(selectedReportsCollection.size())
: Bundle.DeleteReportAction_actionPerformed_showConfirmDialog_single_msg();
String explanation = selectedReportsCollection.size() > 1
? Bundle.DeleteReportAction_showConfirmDialog_multiple_explanation()
: Bundle.DeleteReportAction_showConfirmDialog_single_explanation();
Object[] jOptionPaneContent = {message, explanation};
if (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(null, jOptionPaneContent,
NbBundle.getMessage(Reports.class, "DeleteReportAction.actionPerformed.showConfirmDialog.title"),
Bundle.DeleteReportAction_actionPerformed_showConfirmDialog_title(),
JOptionPane.YES_NO_OPTION)) {
try {
Case.getCurrentCaseThrows().deleteReports(selectedReportsCollection);

View File

@ -50,8 +50,6 @@ import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable.HasCommentStat
import org.sleuthkit.autopsy.coreutils.Logger;
import static org.sleuthkit.autopsy.datamodel.Bundle.*;
import static org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.AbstractFilePropertyType.*;
import org.sleuthkit.autopsy.datamodel.BaseChildFactory.NoSuchEventBusException;
import org.sleuthkit.autopsy.datamodel.BaseChildFactory.RefreshKeysEvent;
import org.sleuthkit.autopsy.ingest.IngestManager;
import static org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent.CONTENT_CHANGED;
import org.sleuthkit.autopsy.ingest.ModuleContentEvent;

View File

@ -1,113 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2021 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.datamodel;
import javax.swing.Action;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.directorytree.CollapseAction;
import org.sleuthkit.autopsy.mainui.nodes.AnalysisResultTypeFactory;
/**
* Analysis Results node support.
*/
@NbBundle.Messages({
"AnalysisResults_name=Analysis Results",
"AnalysisResult_Collapse_All_Name=Collapse All"})
public class AnalysisResults {
/**
* Returns the name of this node that is the key in the children object.
*
* @return The name of this node that is the key in the children object.
*/
public static String getName() {
return Bundle.AnalysisResults_name();
}
/**
* Parent node of all analysis results.
*/
public static class RootNode extends Artifacts.BaseArtifactNode {
private static Children getChildren(long filteringDSObjId) {
return Children.create(
new AnalysisResultTypeFactory(filteringDSObjId > 0 ? filteringDSObjId : null), true);
}
private final long filteringDSObjId;
/**
* Main constructor.
*
* @param filteringDSObjId The data source object id for which results
* should be filtered. If no filtering should
* occur, this number should be less than or
* equal to 0.
*/
RootNode(long filteringDSObjId) {
super(getChildren(filteringDSObjId),
"org/sleuthkit/autopsy/images/analysis_result.png",
AnalysisResults.getName(),
AnalysisResults.getName());
this.filteringDSObjId = filteringDSObjId;
}
public Node clone() {
return new AnalysisResults.RootNode(this.filteringDSObjId);
}
@Override
public Action[] getActions(boolean context) {
Action[] actions = new Action[1];
actions[0] = new CollapseAction(Bundle.AnalysisResult_Collapse_All_Name());
return actions;
}
}
private final long datasourceObjId;
/**
* Main constructor.
*/
public AnalysisResults() {
this(0);
}
/**
* Main constructor.
*
* @param dsObjId The data source object id.
*/
public AnalysisResults(long dsObjId) {
this.datasourceObjId = dsObjId;
}
/**
* Returns whether or not there is a data source object for which results
* should be filtered.
*
* @return Whether or not there is a data source object for which results
* should be filtered.
*/
Long getFilteringDataSourceObjId() {
return datasourceObjId;
}
}

View File

@ -1,81 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2021 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.datamodel;
import org.openide.nodes.Children;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
/**
* Classes for creating nodes for BlackboardArtifacts.
*/
public class Artifacts {
/**
* Base class for a parent node of artifacts.
*/
static class BaseArtifactNode extends DisplayableItemNode {
/**
* Main constructor.
*
* @param children The children of the node.
* @param icon The icon for the node.
* @param name The name identifier of the node.
* @param displayName The display name for the node.
*/
BaseArtifactNode(Children children, String icon, String name, String displayName) {
super(children, Lookups.singleton(name));
super.setName(name);
super.setDisplayName(displayName);
this.setIconBaseWithExtension(icon); //NON-NLS
}
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
return visitor.visit(this);
}
@Override
protected Sheet createSheet() {
Sheet sheet = super.createSheet();
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
if (sheetSet == null) {
sheetSet = Sheet.createPropertiesSet();
sheet.put(sheetSet);
}
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ExtractedContentNode.createSheet.name.name"),
NbBundle.getMessage(this.getClass(), "ExtractedContentNode.createSheet.name.displayName"),
NbBundle.getMessage(this.getClass(), "ExtractedContentNode.createSheet.name.desc"),
super.getDisplayName()));
return sheet;
}
@Override
public String getItemType() {
return getClass().getName();
}
}
}

View File

@ -1,193 +0,0 @@
/*
* Autopsy Forensic Browser
* Copyright 2018-2021 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.datamodel;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.logging.Level;
import java.util.stream.Collectors;
import org.apache.commons.collections.CollectionUtils;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Node;
import org.openide.util.WeakListeners;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.CasePreferences;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.Person;
import org.sleuthkit.datamodel.PersonManager;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
/**
* A child factory to create the top level nodes in the main tree view. These
* nodes are the child nodes of the invisible root node of the tree. The child
* nodes that are created vary with the view option selected by the user: group
* by data type or group by person/host.
*/
public final class AutopsyTreeChildFactory extends ChildFactory.Detachable<Object> {
private static final Set<Case.Events> EVENTS_OF_INTEREST = EnumSet.of(Case.Events.DATA_SOURCE_ADDED,
Case.Events.HOSTS_ADDED,
Case.Events.HOSTS_DELETED,
Case.Events.PERSONS_ADDED,
Case.Events.PERSONS_DELETED,
Case.Events.HOSTS_ADDED_TO_PERSON,
Case.Events.HOSTS_REMOVED_FROM_PERSON
);
private static final Set<String> EVENTS_OF_INTEREST_NAMES = EVENTS_OF_INTEREST.stream()
.map(evt -> evt.name())
.collect(Collectors.toSet());
private static final Logger logger = Logger.getLogger(AutopsyTreeChildFactory.class.getName());
/**
* Listener for application events published when persons and/or hosts are
* added to or deleted from the data model for the current case. If the user
* has selected the group by person/host option for the tree, these events
* mean that the top-level person/host nodes in the tree need to be
* refreshed to reflect the changes.
*/
private final PropertyChangeListener pcl = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName();
if (EVENTS_OF_INTEREST_NAMES.contains(eventType)
&& Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
refreshChildren();
}
}
};
private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null);
@Override
protected void addNotify() {
super.addNotify();
Case.addEventTypeSubscriber(EVENTS_OF_INTEREST, weakPcl);
}
@Override
protected void finalize() throws Throwable {
super.finalize();
Case.removeEventTypeSubscriber(EVENTS_OF_INTEREST, weakPcl);
}
/**
* Creates the keys for the top level nodes in the main tree view. These
* nodes are the child nodes of the invisible root node of the tree. The
* child nodes that are created vary with the view option selected by the
* user: group by data type or group by person/host.
*
* IMPORTANT: Every time a key is added to the keys list, the NetBeans
* framework reacts. To avoid significant performance hits, all of the keys
* need to be added at once.
*
* @param list A list to contain the keys.
*
* @return True, indicating that the list of keys is complete.
*/
@Override
protected boolean createKeys(List<Object> list) {
List<Object> nodes = Collections.emptyList();
try {
SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase();
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
/*
* The user has selected the group by person/host tree view
* option.
*/
PersonManager personManager = tskCase.getPersonManager();
List<Person> persons = personManager.getPersons();
// show persons level if there are persons to be shown
if (!CollectionUtils.isEmpty(persons)) {
nodes = persons.stream()
.map(PersonGrouping::new)
.sorted()
.collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(personManager.getHostsWithoutPersons())) {
nodes.add(new PersonGrouping(null));
}
} else {
// otherwise, just show host level
nodes = tskCase.getHostManager().getAllHosts().stream()
.map(HostGrouping::new)
.sorted()
.collect(Collectors.toList());
}
// either way, add in reports node
nodes.add(new Reports());
} else {
// data source by type view
nodes = Arrays.asList(
new DataSourcesByType(),
new Views(Case.getCurrentCaseThrows().getSleuthkitCase()),
new DataArtifacts(),
new AnalysisResults(),
new OsAccounts(),
new Tags(),
new Reports()
);
}
} catch (NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "Failed to create tree because there is no current case", ex); //NON-NLS
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to create tree because of an error querying the case database", ex); //NON-NLS
}
// add all nodes to the netbeans node list
list.addAll(nodes);
return true;
}
/**
* Creates a node for a given key for the top level nodes in the main tree
* view.
*
* @param key The key.
*
* @return A node for the key.
*/
@Override
protected Node createNodeForKey(Object key) {
Node node = RootContentChildren.createNode(key);
if (node == null) {
logger.log(Level.SEVERE, "Unknown key type: ", key.getClass().getName());
}
return node;
}
/**
* Refreshes the top level nodes in the main tree view.
*/
public void refreshChildren() {
refresh(true);
}
}

View File

@ -1,141 +0,0 @@
/*
* Autopsy Forensic Browser
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.datamodel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.Directory;
import org.sleuthkit.datamodel.FileSystem;
import org.sleuthkit.datamodel.LocalDirectory;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.VolumeSystem;
/**
* Makes the children nodes / keys for a given content object. Has knowledge
* about the structure of the directory tree and what levels should be ignored.
*/
class ContentChildren extends AbstractContentChildren<Content> {
private static final Logger logger = Logger.getLogger(ContentChildren.class.getName());
private final Content parent;
ContentChildren(Content parent) {
super("content_" + Long.toString(parent.getId()));
this.parent = parent;
}
/**
* Get the children of the Content object based on what we want to display.
* As an example, we don't display the direct children of VolumeSystems or
* FileSystems. We hide some of the levels in the tree. This method takes
* care of that and returns the children we want to display
*
* @param parent
*
* @return
*/
private static List<Content> getDisplayChildren(Content parent) {
// what does the content think its children are?
List<Content> tmpChildren;
try {
tmpChildren = parent.getChildren();
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Error getting Content children.", ex); //NON-NLS
tmpChildren = Collections.emptyList();
}
// Cycle through the list and make a new one based
// on what we actually want to display.
List<Content> children = new ArrayList<>();
for (Content c : tmpChildren) {
if (c instanceof VolumeSystem) {
children.addAll(getDisplayChildren(c));
} else if (c instanceof FileSystem) {
children.addAll(getDisplayChildren(c));
} else if (c instanceof Directory) {
Directory dir = (Directory) c;
/*
* For root directories, we want to return their contents.
* Special case though for '.' and '..' entries, because they
* should not have children (and in fact don't in the DB). Other
* drs get treated as files and added as is.
*/
if ((dir.isRoot()) && (dir.getName().equals(".") == false)
&& (dir.getName().equals("..") == false)) {
children.addAll(getDisplayChildren(dir));
} else {
children.add(c);
}
} else if (c instanceof LocalDirectory) {
LocalDirectory localDir = (LocalDirectory) c;
if (localDir.isRoot()) {
children.addAll(getDisplayChildren(localDir));
} else {
children.add(c);
}
} else {
children.add(c);
}
}
return children;
}
@Override
protected List<Content> makeKeys() {
List<Content> contentList = getDisplayChildren(parent);
// Call the getUniquePath method to cache the value for future use
// in the EDT
contentList.forEach(content->{
try {
content.getUniquePath();
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, String.format("Failed attempt to cache the "
+ "unique path of the abstract file instance. Name: %s (objID=%d)",
content.getName(), content.getId()), ex);
}
});
return contentList;
}
@Override
protected void onAdd() {
// No-op
}
/**
* Refresh the list of children due to a change in one (or more) of our
* children (e.g. archive files can change as new content is extracted from
* them).
*/
void refreshChildren() {
refresh(true);
}
@Override
protected void onRemove() {
// No-op
}
}

View File

@ -1,115 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2021 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.datamodel;
import javax.swing.Action;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.directorytree.CollapseAction;
import org.sleuthkit.autopsy.mainui.nodes.DataArtifactTypeFactory;
/**
* Analysis Results node support.
*/
@NbBundle.Messages({
"DataArtifacts_name=Data Artifacts",
"DataArtifacts_Collapse_All_Name=Collapse All"})
public class DataArtifacts {
private static final Logger logger = Logger.getLogger(DataArtifacts.class.getName());
/**
* Returns the name of this node that is the key in the children object.
*
* @return The name of this node that is the key in the children object.
*/
public static String getName() {
return Bundle.DataArtifacts_name();
}
/**
* Parent node of all data artifacts.
*/
public static class RootNode extends Artifacts.BaseArtifactNode {
private static Children getChildren(long filteringDSObjId) {
return Children.create(
new DataArtifactTypeFactory(filteringDSObjId > 0 ? filteringDSObjId : null), true);
}
private final long filteringDSObjId;
/**
* Main constructor.
*
* @param filteringDSObjId The data source object id for which results
* should be filtered. If no filtering should
* occur, this number should be less than or
* equal to 0.
*/
RootNode(long filteringDSObjId) {
super(getChildren(filteringDSObjId),
"org/sleuthkit/autopsy/images/extracted_content.png",
DataArtifacts.getName(),
DataArtifacts.getName());
this.filteringDSObjId = filteringDSObjId;
}
public Node clone() {
return new RootNode(this.filteringDSObjId);
}
@Override
public Action[] getActions(boolean context) {
Action[] actions = new Action[1];
actions[0] = new CollapseAction(Bundle.DataArtifacts_Collapse_All_Name());
return actions;
}
}
private final long datasourceObjId;
/**
* Main constructor.
*/
public DataArtifacts() {
this(0);
}
/**
* Main constructor.
*
* @param dsObjId The data source object id.
*/
public DataArtifacts(long dsObjId) {
this.datasourceObjId = dsObjId;
}
/**
* Returns whether or not there is a data source object for which results
* should be filtered.
*
* @return Whether or not there is a data source object for which results
* should be filtered.
*/
Long getFilteringDataSourceObjId() {
return datasourceObjId;
}
}

View File

@ -31,14 +31,12 @@ import org.sleuthkit.autopsy.actions.AddContentTagAction;
import org.sleuthkit.autopsy.actions.DeleteFileBlackboardArtifactTagAction;
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.datamodel.Reports.ReportNode;
import org.sleuthkit.autopsy.directorytree.ExportCSVAction;
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;
import org.sleuthkit.autopsy.mainui.nodes.OsAccountNode;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.Content;
@ -349,26 +347,6 @@ public class DataModelActionsFactory {
return actionsList;
}
public static List<Action> getActions(Report report, boolean isArtifactSource) {
List<Action> actionsList = new ArrayList<>();
final ReportNode reportNode = new ReportNode(report);
actionsList.add(null); // creates a menu separator
actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, reportNode));
actionsList.add(null); // creates a menu separator
if (isArtifactSource) {
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
}
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(Content content, boolean isArtifactSource) {
if (content instanceof File) {
return getActions((File) content, isArtifactSource);

View File

@ -1,114 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2012-2021 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.datamodel;
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.logging.Level;
import org.openide.nodes.Children;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.mainui.nodes.FileSystemFactory;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskDataException;
/**
* A structural node in the main tree view when the user has selected the group
* by persons/hosts option. Instances of this node appear as children of a node
* representing a data source association with a host, and as a parent of a data
* source node. For example: "Host X" -> "Data Source Y" -> "Data Source Files"
* -> "Data Source Y", where "Data Source Files" is an instance of this node.
*/
public class DataSourceFilesNode extends DisplayableItemNode {
private static final String NAME = NbBundle.getMessage(DataSourceFilesNode.class, "DataSourcesNode.name");
/**
* @return The name used to identify the node of this type with a lookup.
*/
public static String getNameIdentifier() {
return NAME;
}
private final String displayName;
// NOTE: The images passed in via argument will be ignored.
@Deprecated
public DataSourceFilesNode(List<Content> images) {
this(0);
}
public DataSourceFilesNode() {
this(0);
}
public DataSourceFilesNode(long dsObjId) {
super(Children.create(new FileSystemFactory.DataSourceFactory(dsObjId), true), Lookups.singleton(NAME));
displayName = (dsObjId > 0) ? NbBundle.getMessage(DataSourceFilesNode.class, "DataSourcesNode.group_by_datasource.name") : NAME;
init();
}
private void init() {
setName(NAME);
setDisplayName(displayName);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/image.png"); //NON-NLS
}
@Override
public String getItemType() {
return getClass().getName();
}
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
return visitor.visit(this);
}
@Override
protected Sheet createSheet() {
Sheet sheet = super.createSheet();
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
if (sheetSet == null) {
sheetSet = Sheet.createPropertiesSet();
sheet.put(sheetSet);
}
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "DataSourcesNode.createSheet.name.name"),
NbBundle.getMessage(this.getClass(), "DataSourcesNode.createSheet.name.displayName"),
NbBundle.getMessage(this.getClass(), "DataSourcesNode.createSheet.name.desc"),
NAME));
return sheet;
}
}

View File

@ -1,60 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018 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.datamodel;
import java.util.Objects;
import org.sleuthkit.datamodel.DataSource;
/**
* A top level UI grouping of Files, Views, Results, Tags for 'Group by Data
* Source' view of the tree.
*
*/
public class DataSourceGrouping {
private final DataSource dataSource;
public DataSourceGrouping(DataSource dataSource) {
this.dataSource = dataSource;
}
DataSource getDataSource() {
return this.dataSource;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final DataSourceGrouping other = (DataSourceGrouping) obj;
return this.dataSource.getId() == other.getDataSource().getId();
}
@Override
public int hashCode() {
int hash = 7;
hash = 17 * hash + Objects.hashCode(this.dataSource);
return hash;
}
}

View File

@ -1,102 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018 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.datamodel;
import java.util.Arrays;
import java.util.Collections;
import java.util.Optional;
import java.util.logging.Level;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.mainui.nodes.ContentNodeUtil;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.LocalFilesDataSource;
/**
* Data source grouping node - an optional grouping node in the data tree view
*
*/
class DataSourceGroupingNode extends DisplayableItemNode {
private static final Logger logger = Logger.getLogger(DataSourceGroupingNode.class.getName());
/**
* Creates a data source grouping node for the given data source.
*
* @param dataSource specifies the data source
*/
DataSourceGroupingNode(DataSource dataSource) {
super(Optional.ofNullable(createDSGroupingNodeChildren(dataSource))
.orElse(new RootContentChildren(Arrays.asList(Collections.EMPTY_LIST))),
Lookups.singleton(dataSource));
if (dataSource instanceof Image) {
Image image = (Image) dataSource;
super.setName(ContentNodeUtil.getContentName(image.getId()));
super.setDisplayName(image.getName());
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/image.png");
} else if (dataSource instanceof LocalFilesDataSource) {
LocalFilesDataSource localFilesDataSource = (LocalFilesDataSource) dataSource;
super.setName(ContentNodeUtil.getContentName(localFilesDataSource.getId()));
super.setDisplayName(localFilesDataSource.getName());
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/fileset-icon-16.png");
}
}
@Override
public boolean isLeafTypeNode() {
return false;
}
private static RootContentChildren createDSGroupingNodeChildren(DataSource dataSource) {
long dsObjId = dataSource.getId();
try {
return new RootContentChildren(Arrays.asList(
new DataSources(dsObjId),
new Views(Case.getCurrentCaseThrows().getSleuthkitCase(), dsObjId),
new DataArtifacts(dsObjId),
new AnalysisResults(dsObjId),
new OsAccounts(dsObjId),
new Tags(dsObjId)
));
} catch (NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "Error getting open case.", ex); //NON-NLS
return null;
}
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
return visitor.visit(this);
}
@Override
public String getItemType() {
return getClass().getName();
}
}

View File

@ -1,40 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2021 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.datamodel;
/**
* An "Autopsy visitable item" that supplies a
*/
public class DataSources {
private final long datasourceObjId;
public DataSources() {
this(0);
}
public DataSources(long datasourceObjId) {
this.datasourceObjId = datasourceObjId;
}
long filteringDataSourceObjId() {
return this.datasourceObjId;
}
}

View File

@ -1,27 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2021 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.datamodel;
/**
* Signifies a "Data Sources" node with hosts underneath it, and data sources
* (and only data sources) underneath that.
*/
public class DataSourcesByType {
}

View File

@ -1,165 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2021 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.datamodel;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.stream.Collectors;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.openide.util.WeakListeners;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.TskCoreException;
/**
* A top-level structural node (child of the invisible root node) in the main
* tree view when the user has selected the group by data type option. It
* appears as the parent node of the "directory tree" nodes that are the roots
* of the file trees for the individual data sources in a case. For example:
* "Data Sources" -> "Data Source X", "Data Source Y", where "Data Sources" is
* an instance of this node. The siblings of this node are the "Views, "Analysis
* Results," "Os Accounts," "Tags," and "Reports" nodes.
*/
@Messages({
"DataSourcesHostsNode_name=Data Sources"
})
public class DataSourcesNode extends DisplayableItemNode {
/*
* Custom Keys implementation that listens for new data sources being added.
*/
public static class DataSourcesByTypeChildren extends ChildFactory.Detachable<HostDataSources> {
private static final Set<Case.Events> UPDATE_EVTS = EnumSet.of(Case.Events.DATA_SOURCE_ADDED,
Case.Events.HOSTS_ADDED,
Case.Events.HOSTS_DELETED,
Case.Events.HOSTS_UPDATED);
private static final Set<String> UPDATE_EVT_STRS = UPDATE_EVTS.stream()
.map(evt -> evt.name())
.collect(Collectors.toSet());
private static final Logger logger = Logger.getLogger(DataSourcesByTypeChildren.class.getName());
private final PropertyChangeListener pcl = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName();
if (UPDATE_EVT_STRS.contains(eventType)) {
refresh(true);
}
}
};
private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null);
@Override
protected void addNotify() {
Case.addEventTypeSubscriber(UPDATE_EVTS, weakPcl);
}
@Override
protected void finalize() throws Throwable{
Case.removeEventTypeSubscriber(UPDATE_EVTS, weakPcl);
super.finalize();
}
@Override
protected boolean createKeys(List<HostDataSources> toPopulate) {
try {
Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getAllHosts().stream()
.map(HostDataSources::new)
.sorted()
.forEach(toPopulate::add);
} catch (TskCoreException | NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "Error getting data sources: {0}", ex.getMessage()); // NON-NLS
}
return true;
}
@Override
protected Node createNodeForKey(HostDataSources key) {
return new HostNode(key);
}
}
private static final String NAME = Bundle.DataSourcesHostsNode_name();
/**
* @return The name used to identify the node of this type with a lookup.
*/
public static String getNameIdentifier() {
return NAME;
}
/**
* Main constructor.
*/
DataSourcesNode() {
super(Children.create(new DataSourcesByTypeChildren(), true), Lookups.singleton(NAME));
setName(NAME);
setDisplayName(NAME);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/image.png");
}
@Override
public String getItemType() {
return getClass().getName();
}
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
return visitor.visit(this);
}
@Override
protected Sheet createSheet() {
Sheet sheet = super.createSheet();
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
if (sheetSet == null) {
sheetSet = Sheet.createPropertiesSet();
sheet.put(sheetSet);
}
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "DataSourcesNode.createSheet.name.name"),
NbBundle.getMessage(this.getClass(), "DataSourcesNode.createSheet.name.displayName"),
NbBundle.getMessage(this.getClass(), "DataSourcesNode.createSheet.name.desc"),
NAME));
return sheet;
}
}

View File

@ -36,7 +36,6 @@ public interface DisplayableItemNodeVisitor<T> {
/*
* Data Sources Area
*/
T visit(DataSourceFilesNode in);
T visit(LayoutFileNode lfn);
@ -50,10 +49,6 @@ public interface DisplayableItemNodeVisitor<T> {
T visit(FileNode fn);
T visit(ImageNode in);
T visit(VolumeNode vn);
T visit(PoolNode pn);
T visit(SlackFileNode sfn);
@ -64,12 +59,8 @@ public interface DisplayableItemNodeVisitor<T> {
*/
T visit(ViewsNode vn);
T visit(DataSourceGroupingNode dataSourceGroupingNode);
T visit(BlackboardArtifactNode ban);
T visit(Artifacts.BaseArtifactNode ecn);
T visit(CommonAttributeValueNode cavn);
T visit(CommonAttributeSearchResultRootNode cfn);
@ -91,37 +82,11 @@ public interface DisplayableItemNodeVisitor<T> {
*/
T visit(Tags.RootNode node);
/*
* Reports
*/
T visit(Reports.ReportsListNode reportsNode);
T visit(Reports.ReportNode reportNode);
T visit(EmptyNode.MessageNode emptyNode);
/*
* Attachments
*/
T visit(AttachmentNode node);
T visit(OsAccounts.OsAccountListNode node);
T visit(PersonNode node);
T visit(HostNode node);
T visit(DataSourcesNode node);
/*
* Unsupported node
*/
T visit(UnsupportedContentNode ucn);
T visit(LocalFilesDataSourceNode lfdsn);
/**
* Visitor with an implementable default behavior for all types. Override
* specific visit types to not use the default behavior.
@ -188,22 +153,12 @@ public interface DisplayableItemNodeVisitor<T> {
public T visit(FileNode fn) {
return defaultVisit(fn);
}
@Override
public T visit(ImageNode in) {
return defaultVisit(in);
}
@Override
public T visit(PoolNode pn) {
return defaultVisit(pn);
}
@Override
public T visit(VolumeNode vn) {
return defaultVisit(vn);
}
@Override
public T visit(SlackFileNode sfn) {
return defaultVisit(sfn);
@ -214,31 +169,11 @@ public interface DisplayableItemNodeVisitor<T> {
return defaultVisit(ban);
}
@Override
public T visit(Artifacts.BaseArtifactNode ecn) {
return defaultVisit(ecn);
}
@Override
public T visit(EmptyNode.MessageNode ftByMimeTypeEmptyNode) {
return defaultVisit(ftByMimeTypeEmptyNode);
}
@Override
public T visit(ViewsNode vn) {
return defaultVisit(vn);
}
@Override
public T visit(DataSourceGroupingNode dataSourceGroupingNode) {
return defaultVisit(dataSourceGroupingNode);
}
@Override
public T visit(DataSourceFilesNode in) {
return defaultVisit(in);
}
@Override
public T visit(LayoutFileNode lfn) {
return defaultVisit(lfn);
@ -264,49 +199,9 @@ public interface DisplayableItemNodeVisitor<T> {
return defaultVisit(node);
}
@Override
public T visit(Reports.ReportsListNode node) {
return defaultVisit(node);
}
@Override
public T visit(Reports.ReportNode node) {
return defaultVisit(node);
}
@Override
public T visit(AttachmentNode node) {
return defaultVisit(node);
}
@Override
public T visit(OsAccounts.OsAccountListNode node) {
return defaultVisit(node);
}
@Override
public T visit(HostNode node) {
return defaultVisit(node);
}
@Override
public T visit(DataSourcesNode node) {
return defaultVisit(node);
}
@Override
public T visit(PersonNode node) {
return defaultVisit(node);
}
@Override
public T visit(UnsupportedContentNode node) {
return defaultVisit(node);
}
@Override
public T visit(LocalFilesDataSourceNode node) {
return defaultVisit(node);
}
}
}

View File

@ -1,90 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2021 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.datamodel;
import java.util.Objects;
import org.sleuthkit.datamodel.Host;
/**
* A Host node only showing data sources (no results view, reports, etc.).
*/
public class HostDataSources implements Comparable<HostDataSources> {
private final Host host;
/**
* Main constructor.
*
* @param host The host record.
*/
HostDataSources(Host host) {
this.host = host;
}
/**
* @return The pertinent host.
*/
Host getHost() {
return host;
}
@Override
public int hashCode() {
return Objects.hashCode(this.host == null ? 0 : this.host.getHostId());
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final HostDataSources other = (HostDataSources) obj;
long thisId = (this.getHost() == null) ? 0 : this.getHost().getHostId();
long otherId = (other.getHost() == null) ? 0 : other.getHost().getHostId();
return thisId == otherId;
}
/*
* Compares two host groupings to be displayed in a list of children under
* the person.
*/
@Override
public int compareTo(HostDataSources o) {
String thisHost = this.getHost() == null ? null : this.getHost().getName();
String otherHost = o == null || o.getHost() == null ? null : o.getHost().getName();
// push unknown host to bottom
if (thisHost == null && otherHost == null) {
return 0;
} else if (thisHost == null) {
return 1;
} else if (otherHost == null) {
return -1;
}
return thisHost.compareToIgnoreCase(otherHost);
}
}

View File

@ -1,90 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2021 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.datamodel;
import java.util.Objects;
import org.sleuthkit.datamodel.Host;
/**
* A top level UI grouping of data sources under a host.
*/
public class HostGrouping implements Comparable<HostGrouping> {
private final Host host;
/**
* Main constructor.
*
* @param host The host record.
*/
HostGrouping(Host host) {
this.host = host;
}
/**
* @return The pertinent host.
*/
Host getHost() {
return host;
}
@Override
public int hashCode() {
return Objects.hashCode(this.host == null ? 0 : this.host.getHostId());
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final HostGrouping other = (HostGrouping) obj;
long thisId = (this.getHost() == null) ? 0 : this.getHost().getHostId();
long otherId = (other.getHost() == null) ? 0 : other.getHost().getHostId();
return thisId == otherId;
}
/*
* Compares two host groupings to be displayed in a list of children under
* the person.
*/
@Override
public int compareTo(HostGrouping o) {
String thisHost = this.getHost() == null ? null : this.getHost().getName();
String otherHost = o == null || o.getHost() == null ? null : o.getHost().getName();
// push unknown host to bottom
if (thisHost == null && otherHost == null) {
return 0;
} else if (thisHost == null) {
return 1;
} else if (otherHost == null) {
return -1;
}
return thisHost.compareToIgnoreCase(otherHost);
}
}

View File

@ -1,329 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2021 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.datamodel;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.stream.Collectors;
import javax.swing.Action;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.openide.util.WeakListeners;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.casemodule.events.HostsUpdatedEvent;
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.hosts.AssociatePersonsMenuAction;
import org.sleuthkit.autopsy.datamodel.hosts.MergeHostMenuAction;
import org.sleuthkit.autopsy.datamodel.hosts.RemoveParentPersonAction;
import org.sleuthkit.autopsy.mainui.datamodel.FileSystemHostSearchParam;
import org.sleuthkit.autopsy.mainui.nodes.FileSystemFactory;
import org.sleuthkit.autopsy.corecomponents.SelectionResponder;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.Host;
import org.sleuthkit.datamodel.Person;
import org.sleuthkit.datamodel.TskCoreException;
/**
* A node to be displayed in the UI tree for a host and data sources grouped in
* this host.
*/
@NbBundle.Messages(value = {"HostGroupingNode_unknownHostNode_title=Unknown Host"})
public class HostNode extends DisplayableItemNode implements SelectionResponder{
/**
* Provides the data source children for this host.
*/
private static class HostGroupingChildren extends ChildFactory.Detachable<DataSourceGrouping> {
private static final Logger logger = Logger.getLogger(HostGroupingChildren.class.getName());
private final Host host;
private final Function<DataSourceGrouping, Node> dataSourceToNode;
/**
* Main constructor.
*
* @param dataSourceToItem Converts a data source to a node.
* @param host The host.
*/
HostGroupingChildren(Function<DataSourceGrouping, Node> dataSourceToNode, Host host) {
this.host = host;
this.dataSourceToNode = dataSourceToNode;
}
/**
* Listener for handling DATA_SOURCE_ADDED / HOST_DELETED events.
* A host may have been deleted as part of a merge, which means its data sources could
* have moved to a different host requiring a refresh.
*/
private final PropertyChangeListener dataSourceAddedPcl = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName();
if (eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())
|| eventType.equals(Case.Events.HOSTS_DELETED.toString())) {
refresh(true);
}
}
};
private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(dataSourceAddedPcl, null);
@Override
protected void addNotify() {
super.addNotify();
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.DATA_SOURCE_ADDED, Case.Events.HOSTS_DELETED), weakPcl);
}
@Override
protected void finalize() throws Throwable {
super.finalize();
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.DATA_SOURCE_ADDED, Case.Events.HOSTS_DELETED), weakPcl);
}
@Override
protected Node createNodeForKey(DataSourceGrouping key) {
return this.dataSourceToNode.apply(key);
}
@Override
protected boolean createKeys(List<DataSourceGrouping> toPopulate) {
List<DataSource> dataSources = null;
try {
dataSources = Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getDataSourcesForHost(host);
} catch (NoCurrentCaseException | TskCoreException ex) {
String hostName = host == null || host.getName() == null ? "<unknown>" : host.getName();
logger.log(Level.WARNING, String.format("Unable to get data sources for host: %s", hostName), ex);
}
if (dataSources != null) {
toPopulate.addAll(dataSources.stream()
.filter(ds -> ds != null)
.map(DataSourceGrouping::new)
.sorted((a, b) -> getNameOrEmpty(a).compareToIgnoreCase(getNameOrEmpty(b)))
.collect(Collectors.toList()));
}
return true;
}
/**
* Get name for data source in data source grouping node or empty
* string.
*
* @param dsGroup The data source grouping.
* @return The name or empty if none exists.
*/
private String getNameOrEmpty(DataSourceGrouping dsGroup) {
return (dsGroup == null || dsGroup.getDataSource() == null || dsGroup.getDataSource().getName() == null)
? ""
: dsGroup.getDataSource().getName();
}
}
private static final Logger logger = Logger.getLogger(HostNode.class.getName());
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/host.png";
/**
* Means of creating just data source nodes underneath the host (i.e. no
* results, reports, etc.)
*/
private static final Function<DataSourceGrouping, Node> HOST_DATA_SOURCES = key -> {
return RootContentChildren.createNode(key);
};
/**
* Shows data sources with results, reports, etc.
*/
private static final Function<DataSourceGrouping, Node> HOST_GROUPING_CONVERTER = key -> {
if (key == null || key.getDataSource() == null) {
return null;
}
return new DataSourceGroupingNode(key.getDataSource());
};
/**
* Listener for handling host change events.
*/
private final PropertyChangeListener hostChangePcl = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName();
if (hostId != null && eventType.equals(Case.Events.HOSTS_UPDATED.toString()) && evt instanceof HostsUpdatedEvent) {
((HostsUpdatedEvent) evt).getHosts().stream()
.filter(h -> h != null && h.getHostId() == hostId)
.findFirst()
.ifPresent((newHost) -> {
setName(newHost.getName());
setDisplayName(newHost.getName());
});
}
}
};
private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(hostChangePcl, null);
/*
* Get the host name or 'unknown host' if null.
*
* @param host The host.
* @return The display name.
*/
private static String getHostName(Host host) {
return (host == null || host.getName() == null)
? Bundle.HostGroupingNode_unknownHostNode_title()
: host.getName();
}
private final Host host;
private final Long hostId;
/**
* Main constructor for HostDataSources key where data source children
* should be displayed without additional results, reports, etc.
*
* @param hosts The HostDataSources key.
*/
HostNode(HostDataSources hosts) {
this(Children.create(new FileSystemFactory(hosts.getHost()), true), hosts.getHost());
}
/**
* Main constructor for HostGrouping key where data sources should be
* displayed with results, reports, etc.
*
* @param hostGrouping The HostGrouping key.
*/
HostNode(HostGrouping hostGrouping) {
this(Children.create(new HostGroupingChildren(HOST_GROUPING_CONVERTER, hostGrouping.getHost()), true), hostGrouping.getHost());
}
/**
* Constructor.
*
* @param children The children for this host node.
* @param host The host.
*/
private HostNode(Children children, Host host) {
this(children, host, getHostName(host));
}
/**
* Constructor.
*
* @param children The children for this host node.
* @param host The host.
* @param displayName The displayName.
*/
private HostNode(Children children, Host host, String displayName) {
super(children,
host == null ? Lookups.fixed(displayName) : Lookups.fixed(host, displayName));
hostId = host == null ? null : host.getHostId();
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.HOSTS_UPDATED), weakPcl);
super.setName(displayName);
super.setDisplayName(displayName);
this.setIconBaseWithExtension(ICON_PATH);
this.host = host;
}
@Override
public void respondSelection(DataResultTopComponent dataResultPanel) {
dataResultPanel.displayFileSystemForHost(new FileSystemHostSearchParam(host.getHostId()));
}
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override
public String getItemType() {
return getClass().getName();
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
return visitor.visit(this);
}
@Messages({
"HostNode_createSheet_nameProperty=Name",})
@Override
protected Sheet createSheet() {
Sheet sheet = Sheet.createDefault();
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
if (sheetSet == null) {
sheetSet = Sheet.createPropertiesSet();
sheet.put(sheetSet);
}
sheetSet.put(new NodeProperty<>("Name", Bundle.HostNode_createSheet_nameProperty(), "", getDisplayName())); //NON-NLS
return sheet;
}
@Override
@Messages({"HostNode_actions_associateWithExisting=Associate with existing person...",
"HostNode_actions_associateWithNew=Associate with new person...",
"# {0} - hostName",
"HostNode_actions_removeFromPerson=Remove from person ({0})"})
public Action[] getActions(boolean context) {
List<Action> actionsList = new ArrayList<>();
// if there is a host, then provide actions
if (this.host != null) {
// Add the appropriate Person action
Optional<Person> parent;
try {
parent = Case.getCurrentCaseThrows().getSleuthkitCase().getPersonManager().getPerson(this.host);
} catch (NoCurrentCaseException | TskCoreException ex) {
logger.log(Level.WARNING, String.format("Error fetching parent person of host: %s", this.host.getName() == null ? "<null>" : this.host.getName()), ex);
return new Action[0];
}
// if there is a parent, only give option to remove parent person.
if (parent.isPresent()) {
actionsList.add(new RemoveParentPersonAction(this.host, parent.get()));
} else {
actionsList.add(new AssociatePersonsMenuAction(this.host));
}
// Add option to merge hosts
actionsList.add(new MergeHostMenuAction(this.host));
}
return actionsList.toArray(new Action[actionsList.size()]);
}
}

View File

@ -1,251 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2012-2021 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.datamodel;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import javax.swing.Action;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.DeleteDataSourceAction;
import org.sleuthkit.autopsy.datasourcesummary.ui.ViewSummaryInformationAction;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.directorytree.ExplorerNodeActionVisitor;
import org.sleuthkit.autopsy.directorytree.FileSearchTreeAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModulesAction;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.VirtualDirectory;
import org.sleuthkit.autopsy.datamodel.BaseChildFactory.NoSuchEventBusException;
import org.sleuthkit.datamodel.Tag;
/**
* This class is used to represent the "Node" for the image. The children of
* this node are volumes.
*/
public class ImageNode extends AbstractContentNode<Image> {
private static final Logger logger = Logger.getLogger(ImageNode.class.getName());
private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.CONTENT_CHANGED);
/**
* Helper so that the display name and the name used in building the path
* are determined the same way.
*
* @param i Image to get the name of
*
* @return short name for the Image
*/
static String nameForImage(Image i) {
return i.getName();
}
/**
* @param img
*/
public ImageNode(Image img) {
super(img);
// set name, display name, and icon
String imgName = nameForImage(img);
this.setDisplayName(imgName);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hard-drive-icon.jpg"); //NON-NLS
// Listen for ingest events so that we can detect new added files (e.g. carved)
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
// Listen for case events so that we can detect when case is closed
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
}
private void removeListeners() {
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
}
/**
* Right click action for this node
*
* @param context
*
* @return
*/
@Override
@Messages({"ImageNode.action.runIngestMods.text=Run Ingest Modules",
"ImageNode.getActions.openFileSearchByAttr.text=Open File Search by Attributes"})
public Action[] getActions(boolean context) {
List<Action> actionsList = new ArrayList<>();
actionsList.addAll(ExplorerNodeActionVisitor.getActions(content));
actionsList.add(new FileSearchTreeAction(Bundle.ImageNode_getActions_openFileSearchByAttr_text(), content.getId()));
actionsList.add(new ViewSummaryInformationAction(content.getId()));
actionsList.add(new RunIngestModulesAction(Collections.<Content>singletonList(content)));
actionsList.add(new NewWindowViewAction(NbBundle.getMessage(this.getClass(), "ImageNode.getActions.viewInNewWin.text"), this));
actionsList.add(new DeleteDataSourceAction(content.getId()));
actionsList.add(null);
actionsList.addAll(Arrays.asList(super.getActions(true)));
return actionsList.toArray(new Action[0]);
}
@Override
@Messages({"ImageNode.createSheet.size.name=Size (Bytes)",
"ImageNode.createSheet.size.displayName=Size (Bytes)",
"ImageNode.createSheet.size.desc=Size of the data source in bytes.",
"ImageNode.createSheet.type.name=Type",
"ImageNode.createSheet.type.displayName=Type",
"ImageNode.createSheet.type.desc=Type of the image.",
"ImageNode.createSheet.type.text=Image",
"ImageNode.createSheet.sectorSize.name=Sector Size (Bytes)",
"ImageNode.createSheet.sectorSize.displayName=Sector Size (Bytes)",
"ImageNode.createSheet.sectorSize.desc=Sector size of the image in bytes.",
"ImageNode.createSheet.timezone.name=Timezone",
"ImageNode.createSheet.timezone.displayName=Timezone",
"ImageNode.createSheet.timezone.desc=Timezone of the image",
"ImageNode.createSheet.deviceId.name=Device ID",
"ImageNode.createSheet.deviceId.displayName=Device ID",
"ImageNode.createSheet.deviceId.desc=Device ID of the image"})
protected Sheet createSheet() {
Sheet sheet = super.createSheet();
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
if (sheetSet == null) {
sheetSet = Sheet.createPropertiesSet();
sheet.put(sheetSet);
}
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ImageNode.createSheet.name.name"),
NbBundle.getMessage(this.getClass(), "ImageNode.createSheet.name.displayName"),
NbBundle.getMessage(this.getClass(), "ImageNode.createSheet.name.desc"),
getDisplayName()));
sheetSet.put(new NodeProperty<>(Bundle.ImageNode_createSheet_type_name(),
Bundle.ImageNode_createSheet_type_displayName(),
Bundle.ImageNode_createSheet_type_desc(),
Bundle.ImageNode_createSheet_type_text()));
sheetSet.put(new NodeProperty<>(Bundle.ImageNode_createSheet_size_name(),
Bundle.ImageNode_createSheet_size_displayName(),
Bundle.ImageNode_createSheet_size_desc(),
this.content.getSize()));
sheetSet.put(new NodeProperty<>(Bundle.ImageNode_createSheet_sectorSize_name(),
Bundle.ImageNode_createSheet_sectorSize_displayName(),
Bundle.ImageNode_createSheet_sectorSize_desc(),
this.content.getSsize()));
sheetSet.put(new NodeProperty<>(Bundle.ImageNode_createSheet_timezone_name(),
Bundle.ImageNode_createSheet_timezone_displayName(),
Bundle.ImageNode_createSheet_timezone_desc(),
this.content.getTimeZone()));
sheetSet.put(new NodeProperty<>(Bundle.ImageNode_createSheet_deviceId_name(),
Bundle.ImageNode_createSheet_deviceId_displayName(),
Bundle.ImageNode_createSheet_deviceId_desc(),
content.getDeviceId()));
return sheet;
}
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
return visitor.visit(this);
}
@Override
public String getItemType() {
return getClass().getName();
}
/*
* This property change listener refreshes the tree when a new file is
* carved out of this image (i.e, the image is being treated as raw bytes
* and was ingested by the RawDSProcessor).
*/
private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
String eventType = evt.getPropertyName();
// See if the new file is a child of ours
if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) {
if ((evt.getOldValue() instanceof ModuleContentEvent) == false) {
return;
}
ModuleContentEvent moduleContentEvent = (ModuleContentEvent) evt.getOldValue();
if ((moduleContentEvent.getSource() instanceof Content) == false) {
return;
}
Content newContent = (Content) moduleContentEvent.getSource();
try {
Content parent = newContent.getParent();
if (parent != null) {
// Is this a new carved file?
if (parent.getName().equals(VirtualDirectory.NAME_CARVED)) {
// Is this new carved file for this data source?
if (newContent.getDataSource().getId() == getContent().getDataSource().getId()) {
// Find the image (if any) associated with the new content and
// trigger a refresh if it matches the image wrapped by this node.
while ((parent = parent.getParent()) != null) {
if (parent.getId() == getContent().getId()) {
BaseChildFactory.post(getName(), new BaseChildFactory.RefreshKeysEvent());
break;
}
}
}
}
}
} catch (TskCoreException ex) {
// Do nothing.
} catch (NoSuchEventBusException ex) {
logger.log(Level.WARNING, "Failed to post key refresh event.", ex); // NON-NLS
}
} else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
if (evt.getNewValue() == null) {
// case was closed. Remove listeners so that we don't get called with a stale case handle
removeListeners();
}
}
};
/**
* Reads and returns a list of all tags associated with this content node.
*
* Null implementation of an abstract method.
*
* @return list of tags associated with the node.
*/
@Override
protected List<Tag> getAllTagsFromDatabase() {
return new ArrayList<>();
}
}

View File

@ -1,94 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2021 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.datamodel;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.sleuthkit.datamodel.LocalFilesDataSource;
/**
*
*
*/
public class LocalFilesDataSourceNode extends VirtualDirectoryNode {
private final LocalFilesDataSource localFileDataSource;
public LocalFilesDataSourceNode(LocalFilesDataSource ld) {
super(ld);
localFileDataSource = ld;
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/fileset-icon-16.png"); //NON-NLS
}
@Override
@NbBundle.Messages({"LocalFilesDataSourceNode.createSheet.size.name=Size (Bytes)",
"LocalFilesDataSourceNode.createSheet.size.displayName=Size (Bytes)",
"LocalFilesDataSourceNode.createSheet.size.desc=Size of the data source in bytes.",
"LocalFilesDataSourceNode.createSheet.type.name=Type",
"LocalFilesDataSourceNode.createSheet.type.displayName=Type",
"LocalFilesDataSourceNode.createSheet.type.desc=Type of the image.",
"LocalFilesDataSourceNode.createSheet.type.text=Logical File Set",
"LocalFilesDataSourceNode.createSheet.timezone.name=Timezone",
"LocalFilesDataSourceNode.createSheet.timezone.displayName=Timezone",
"LocalFilesDataSourceNode.createSheet.timezone.desc=Timezone of the image",
"LocalFilesDataSourceNode.createSheet.deviceId.name=Device ID",
"LocalFilesDataSourceNode.createSheet.deviceId.displayName=Device ID",
"LocalFilesDataSourceNode.createSheet.deviceId.desc=Device ID of the image",
"LocalFilesDataSourceNode.createSheet.name.name=Name",
"LocalFilesDataSourceNode.createSheet.name.displayName=Name",
"LocalFilesDataSourceNode.createSheet.name.desc=no description",
"LocalFilesDataSourceNode.createSheet.noDesc=no description",})
protected Sheet createSheet() {
Sheet sheet = new Sheet();
Sheet.Set sheetSet = Sheet.createPropertiesSet();
sheet.put(sheetSet);
sheetSet.put(new NodeProperty<>(Bundle.LocalFilesDataSourceNode_createSheet_name_name(),
Bundle.LocalFilesDataSourceNode_createSheet_name_displayName(),
Bundle.LocalFilesDataSourceNode_createSheet_name_desc(),
getName()));
sheetSet.put(new NodeProperty<>(Bundle.LocalFilesDataSourceNode_createSheet_type_name(),
Bundle.LocalFilesDataSourceNode_createSheet_type_displayName(),
Bundle.LocalFilesDataSourceNode_createSheet_type_desc(),
Bundle.LocalFilesDataSourceNode_createSheet_type_text()));
sheetSet.put(new NodeProperty<>(Bundle.LocalFilesDataSourceNode_createSheet_size_name(),
Bundle.LocalFilesDataSourceNode_createSheet_size_displayName(),
Bundle.LocalFilesDataSourceNode_createSheet_size_desc(),
this.content.getSize()));
sheetSet.put(new NodeProperty<>(Bundle.LocalFilesDataSourceNode_createSheet_timezone_name(),
Bundle.LocalFilesDataSourceNode_createSheet_timezone_displayName(),
Bundle.LocalFilesDataSourceNode_createSheet_timezone_desc(),
""));
sheetSet.put(new NodeProperty<>(Bundle.LocalFilesDataSourceNode_createSheet_deviceId_name(),
Bundle.LocalFilesDataSourceNode_createSheet_deviceId_displayName(),
Bundle.LocalFilesDataSourceNode_createSheet_deviceId_desc(),
localFileDataSource.getDeviceId()));
return sheet;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
return visitor.visit(this);
}
}

View File

@ -1,91 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2021 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.datamodel;
import org.openide.nodes.Children;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
import org.sleuthkit.autopsy.corecomponents.SelectionResponder;
import org.sleuthkit.autopsy.mainui.datamodel.OsAccountsSearchParams;
/**
* Implements the OS Accounts subnode of Results in the Autopsy tree.
*/
public final class OsAccounts {
private static final String LIST_NAME = Bundle.OsAccount_listNode_name();
private final long filteringDSObjId;
/**
* Returns the name of the OsAccountListNode to be used for id purposes.
*
* @return The name of the OsAccountListNode to be used for id purposes.
*/
public static String getListName() {
return LIST_NAME;
}
public OsAccounts() {
this(0);
}
public OsAccounts(long objId) {
this.filteringDSObjId = objId;
}
@Messages({
"OsAccount_listNode_name=OS Accounts"
})
/**
* The root node of the OS Accounts subtree.
*/
public final class OsAccountListNode extends DisplayableItemNode implements SelectionResponder {
/**
* Construct a new OsAccountListNode.
*/
public OsAccountListNode() {
super(Children.LEAF);
setName(LIST_NAME);
setDisplayName(LIST_NAME);
setIconBaseWithExtension("org/sleuthkit/autopsy/images/os-account.png");
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
return visitor.visit(this);
}
@Override
public boolean isLeafTypeNode() {
return true;
}
@Override
public String getItemType() {
return getClass().getName();
}
@Override
public void respondSelection(DataResultTopComponent dataResultPanel) {
dataResultPanel.displayOsAccounts(new OsAccountsSearchParams(filteringDSObjId == 0 ? null : filteringDSObjId));
}
}
}

View File

@ -1,91 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2021 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.datamodel;
import java.util.Objects;
import org.sleuthkit.datamodel.Person;
/**
* A top level UI grouping of hosts under a person.
*/
public class PersonGrouping implements Comparable<PersonGrouping> {
private final Person person;
/**
* Main constructor.
*
* @param person The person to be represented.
*/
PersonGrouping(Person person) {
this.person = person;
}
/**
* @return The person to be represented.
*/
Person getPerson() {
return person;
}
@Override
public int hashCode() {
return Objects.hashCode(this.person == null ? 0 : this.person.getPersonId());
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final PersonGrouping other = (PersonGrouping) obj;
long thisId = (this.getPerson() == null) ? 0 : this.getPerson().getPersonId();
long otherId = (other.getPerson() == null) ? 0 : other.getPerson().getPersonId();
return thisId == otherId;
}
/*
* Compares two person groupings to be displayed in a list of children under
* the root of the tree.
*/
@Override
public int compareTo(PersonGrouping o) {
String thisPerson = this.getPerson() == null ? null : this.getPerson().getName();
String otherPerson = o == null || o.getPerson() == null ? null : o.getPerson().getName();
// push unknown host to bottom
if (thisPerson == null && otherPerson == null) {
return 0;
} else if (thisPerson == null) {
return 1;
} else if (otherPerson == null) {
return -1;
}
return thisPerson.compareToIgnoreCase(otherPerson);
}
}

View File

@ -1,267 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2021 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.datamodel;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.stream.Collectors;
import javax.swing.Action;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.openide.util.WeakListeners;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.casemodule.events.PersonsUpdatedEvent;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.persons.DeletePersonAction;
import org.sleuthkit.autopsy.datamodel.persons.EditPersonAction;
import org.sleuthkit.datamodel.Host;
import org.sleuthkit.datamodel.Person;
import org.sleuthkit.datamodel.TskCoreException;
/**
* A main tree view node that represents a person in a case. Its child nodes, if
* any, represent hosts in the case. There must be at least one person in a case
* for the person nodes layer to appear. If the persons layer is present, any
* hosts that are not associated with a person are grouped under an "Unknown
* Persons" person node.
*/
@NbBundle.Messages(value = {"PersonNode_unknownPersonNode_title=Unknown Persons"})
public class PersonNode extends DisplayableItemNode {
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/person.png";
/**
* Returns the id of an unknown persons node. This can be used with a node
* lookup.
*
* @return The id of an unknown persons node.
*/
public static String getUnknownPersonId() {
return Bundle.PersonNode_unknownPersonNode_title();
}
/**
* Responsible for creating the host children of this person.
*/
private static class PersonChildren extends ChildFactory.Detachable<HostGrouping> {
private static final Logger logger = Logger.getLogger(PersonChildren.class.getName());
private static final Set<Case.Events> HOST_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.HOSTS_ADDED,
Case.Events.HOSTS_ADDED,
Case.Events.HOSTS_DELETED,
Case.Events.HOSTS_ADDED_TO_PERSON,
Case.Events.HOSTS_REMOVED_FROM_PERSON);
private static final Set<String> HOST_EVENTS_OF_INTEREST_NAMES = HOST_EVENTS_OF_INTEREST.stream()
.map(ev -> ev.name())
.collect(Collectors.toSet());
private final Person person;
/**
* Main constructor.
*
* @param person The person record.
*/
PersonChildren(Person person) {
this.person = person;
}
/**
* Listener for application events that are published when hosts are
* added to or deleted from a case, and for events published when the
* associations between persons and hosts change. If the user has
* selected the group by person/host option for the main tree view,
* these events mean that person nodes in the tree need to be refreshed
* to reflect the structural changes.
*/
private final PropertyChangeListener hostAddedDeletedPcl = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName();
if (eventType != null && HOST_EVENTS_OF_INTEREST_NAMES.contains(eventType)) {
refresh(true);
}
}
};
private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(hostAddedDeletedPcl, null);
@Override
protected void addNotify() {
Case.addEventTypeSubscriber(HOST_EVENTS_OF_INTEREST, weakPcl);
}
@Override
protected void finalize() throws Throwable {
super.finalize();
Case.removeEventTypeSubscriber(HOST_EVENTS_OF_INTEREST, weakPcl);
}
@Override
protected HostNode createNodeForKey(HostGrouping key) {
return key == null ? null : new HostNode(key);
}
@Override
protected boolean createKeys(List<HostGrouping> toPopulate) {
List<Host> hosts = Collections.emptyList();
try {
if (person != null) {
hosts = Case.getCurrentCaseThrows().getSleuthkitCase().getPersonManager().getHostsForPerson(person);
} else {
// This is the "Unknown Persons" node, get the hosts that are not associated with a person.
hosts = Case.getCurrentCaseThrows().getSleuthkitCase().getPersonManager().getHostsWithoutPersons();
}
} catch (NoCurrentCaseException | TskCoreException ex) {
String personName = person == null || person.getName() == null ? "<unknown>" : person.getName();
logger.log(Level.WARNING, String.format("Unable to get data sources for host: %s", personName), ex);
}
toPopulate.addAll(hosts.stream()
.map(HostGrouping::new)
.sorted()
.collect(Collectors.toList()));
return true;
}
}
private final Person person;
private final Long personId;
/**
* Listener for application events that are published when the properties of
* persons in the case change.
*/
private final PropertyChangeListener personChangePcl = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName();
if (personId != null && eventType.equals(Case.Events.PERSONS_UPDATED.toString()) && evt instanceof PersonsUpdatedEvent) {
((PersonsUpdatedEvent) evt).getNewValue().stream()
.filter(p -> p != null && p.getPersonId() == personId)
.findFirst()
.ifPresent((newPerson) -> {
setName(newPerson.getName());
setDisplayName(newPerson.getName());
});
}
}
};
private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(personChangePcl, null);
/**
* Gets the display name for this person or "Unknown Persons".
*
* @param person The person.
*
* @return The non-empty string for the display name.
*/
private static String getDisplayName(Person person) {
return (person == null || person.getName() == null)
? getUnknownPersonId()
: person.getName();
}
/**
* Main constructor.
*
* @param person The person record to be represented.
*/
PersonNode(Person person) {
this(person, getDisplayName(person));
}
/**
* Constructor.
*
* @param person The person.
* @param displayName The display name for the person.
*/
private PersonNode(Person person, String displayName) {
super(Children.create(new PersonChildren(person), true),
person == null ? Lookups.fixed(displayName) : Lookups.fixed(person, displayName));
super.setName(displayName);
super.setDisplayName(displayName);
this.setIconBaseWithExtension(ICON_PATH);
this.person = person;
this.personId = person == null ? null : person.getPersonId();
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.PERSONS_UPDATED), weakPcl);
}
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override
public String getItemType() {
return getClass().getName();
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
return visitor.visit(this);
}
@NbBundle.Messages({
"PersonGroupingNode_createSheet_nameProperty=Name",})
@Override
protected Sheet createSheet() {
Sheet sheet = Sheet.createDefault();
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
if (sheetSet == null) {
sheetSet = Sheet.createPropertiesSet();
sheet.put(sheetSet);
}
sheetSet.put(new NodeProperty<>("Name", Bundle.PersonGroupingNode_createSheet_nameProperty(), "", getDisplayName())); //NON-NLS
return sheet;
}
@Override
@Messages({"PersonGroupingNode_actions_rename=Rename Person...",
"PersonGroupingNode_actions_delete=Delete Person"})
public Action[] getActions(boolean context) {
if (this.person == null) {
return new Action[0];
} else {
return new Action[]{
new EditPersonAction(this.person),
new DeletePersonAction(this.person),
null
};
}
}
}

View File

@ -1,299 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2018 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.datamodel;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JOptionPane;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
import org.sleuthkit.datamodel.Report;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Implements the Reports subtree of the Autopsy tree.
*/
public final class Reports {
private static final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
/**
* The root node of the Reports subtree of the Autopsy tree.
*/
public static final class ReportsListNode extends DisplayableItemNode {
private static final long serialVersionUID = 1L;
private static final String DISPLAY_NAME = NbBundle.getMessage(ReportsListNode.class, "ReportsListNode.displayName");
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/report_16.png"; //NON-NLS
public ReportsListNode() {
super(Children.create(new ReportNodeFactory(), true));
setName(DISPLAY_NAME);
setDisplayName(DISPLAY_NAME);
this.setIconBaseWithExtension(ICON_PATH);
}
@Override
public boolean isLeafTypeNode() {
return true;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
// - GetPopupActionsDisplayableItemNodeVisitor.visit() returns null.
// - GetPreferredActionsDisplayableItemNodeVisitor.visit() returns null.
// - IsLeafItemVisitor.visit() returns false.
// - ShowItemVisitor.visit() returns true.
return visitor.visit(this);
}
@Override
public String getItemType() {
return getClass().getName();
}
}
/**
* The child node factory that creates ReportNode children for a
* ReportsListNode.
*/
private static final class ReportNodeFactory extends ChildFactory<Report> {
private static final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.REPORT_ADDED, Case.Events.REPORT_DELETED);
ReportNodeFactory() {
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, (PropertyChangeEvent evt) -> {
String eventType = evt.getPropertyName();
if (eventType.equals(Case.Events.REPORT_ADDED.toString()) || eventType.equals(Case.Events.REPORT_DELETED.toString())) {
/**
* Checking for a current case is a stop gap measure until a
* different way of handling the closing of cases is worked
* out. Currently, remote events may be received for a case
* that is already closed.
*/
try {
Case.getCurrentCaseThrows();
ReportNodeFactory.this.refresh(true);
} catch (NoCurrentCaseException notUsed) {
/**
* Case is closed, do nothing.
*/
}
}
});
}
@Override
protected boolean createKeys(List<Report> keys) {
try {
keys.addAll(Case.getCurrentCaseThrows().getAllReports());
} catch (TskCoreException | NoCurrentCaseException ex) {
Logger.getLogger(Reports.ReportNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get reports", ex); //NON-NLS
}
return true;
}
@Override
protected Node createNodeForKey(Report key) {
return new ReportNode(key);
}
}
/**
* A leaf node in the Reports subtree of the Autopsy tree, wraps a Report
* object.
*/
public static final class ReportNode extends DisplayableItemNode {
private static final long serialVersionUID = 1L;
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/report_16.png"; //NON-NLS
private final Report report;
ReportNode(Report report) {
super(Children.LEAF, Lookups.fixed(report));
this.report = report;
super.setName(this.report.getSourceModuleName());
super.setDisplayName(this.report.getSourceModuleName());
this.setIconBaseWithExtension(ICON_PATH);
}
@Override
public boolean isLeafTypeNode() {
return true;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
// - GetPopupActionsDisplayableItemNodeVisitor.visit() calls getActions().
// - GetPreferredActionsDisplayableItemNodeVisitor.visit() calls getPreferredAction().
// - IsLeafItemVisitor.visit() returns true.
// - ShowItemVisitor.visit() returns true.
return visitor.visit(this);
}
@Override
protected Sheet createSheet() {
Sheet sheet = super.createSheet();
Sheet.Set propertiesSet = sheet.get(Sheet.PROPERTIES);
if (propertiesSet == null) {
propertiesSet = Sheet.createPropertiesSet();
sheet.put(propertiesSet);
}
propertiesSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ReportNode.sourceModuleNameProperty.name"),
NbBundle.getMessage(this.getClass(), "ReportNode.sourceModuleNameProperty.displayName"),
NbBundle.getMessage(this.getClass(), "ReportNode.sourceModuleNameProperty.desc"),
this.report.getSourceModuleName()));
propertiesSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ReportNode.reportNameProperty.name"),
NbBundle.getMessage(this.getClass(), "ReportNode.reportNameProperty.displayName"),
NbBundle.getMessage(this.getClass(), "ReportNode.reportNameProperty.desc"),
this.report.getReportName()));
propertiesSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ReportNode.createdTimeProperty.name"),
NbBundle.getMessage(this.getClass(), "ReportNode.createdTimeProperty.displayName"),
NbBundle.getMessage(this.getClass(), "ReportNode.createdTimeProperty.desc"),
dateFormatter.format(new java.util.Date(this.report.getCreatedTime() * 1000))));
propertiesSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ReportNode.pathProperty.name"),
NbBundle.getMessage(this.getClass(), "ReportNode.pathProperty.displayName"),
NbBundle.getMessage(this.getClass(), "ReportNode.pathProperty.desc"),
this.report.getPath()));
return sheet;
}
@Override
public Action[] getActions(boolean popup) {
List<Action> actions = new ArrayList<>();
actions.add(new OpenReportAction());
actions.add(DeleteReportAction.getInstance());
actions.add(null);
actions.addAll(Arrays.asList(super.getActions(true)));
return actions.toArray(new Action[actions.size()]);
}
@Override
public AbstractAction getPreferredAction() {
return new OpenReportAction();
}
@Override
public String getItemType() {
return getClass().getName();
}
private static class DeleteReportAction extends AbstractAction {
private static final long serialVersionUID = 1L;
private static DeleteReportAction instance;
// 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 DeleteReportAction getInstance() {
if (instance == null) {
instance = new DeleteReportAction();
}
if (Utilities.actionsGlobalContext().lookupAll(Report.class).size() == 1) {
instance.putValue(Action.NAME, NbBundle.getMessage(Reports.class, "DeleteReportAction.actionDisplayName.singleReport"));
} else {
instance.putValue(Action.NAME, NbBundle.getMessage(Reports.class, "DeleteReportAction.actionDisplayName.multipleReports"));
}
return instance;
}
/**
* Do not instantiate directly. Use
* DeleteReportAction.getInstance(), instead.
*/
private DeleteReportAction() {
}
@NbBundle.Messages({
"DeleteReportAction.showConfirmDialog.single.explanation=The report will remain on disk.",
"DeleteReportAction.showConfirmDialog.multiple.explanation=The reports will remain on disk.",
"DeleteReportAction.showConfirmDialog.errorMsg=An error occurred while deleting the reports."})
@Override
public void actionPerformed(ActionEvent e) {
Collection<? extends Report> selectedReportsCollection = Utilities.actionsGlobalContext().lookupAll(Report.class);
String message = selectedReportsCollection.size() > 1
? NbBundle.getMessage(Reports.class, "DeleteReportAction.actionPerformed.showConfirmDialog.multiple.msg", selectedReportsCollection.size())
: NbBundle.getMessage(Reports.class, "DeleteReportAction.actionPerformed.showConfirmDialog.single.msg");
String explanation = selectedReportsCollection.size() > 1
? Bundle.DeleteReportAction_showConfirmDialog_multiple_explanation()
: Bundle.DeleteReportAction_showConfirmDialog_single_explanation();
Object[] jOptionPaneContent = {message, explanation};
if (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(null, jOptionPaneContent,
NbBundle.getMessage(Reports.class, "DeleteReportAction.actionPerformed.showConfirmDialog.title"),
JOptionPane.YES_NO_OPTION)) {
try {
Case.getCurrentCaseThrows().deleteReports(selectedReportsCollection);
} catch (TskCoreException | NoCurrentCaseException ex) {
Logger.getLogger(DeleteReportAction.class.getName()).log(Level.SEVERE, "Error deleting reports", ex); // NON-NLS
MessageNotifyUtil.Message.error(Bundle.DeleteReportAction_showConfirmDialog_errorMsg());
}
}
}
}
private final class OpenReportAction extends AbstractAction {
private static final long serialVersionUID = 1L;
private OpenReportAction() {
super(NbBundle.getMessage(OpenReportAction.class, "OpenReportAction.actionDisplayName"));
}
@Override
public void actionPerformed(ActionEvent e) {
String reportPath = ReportNode.this.report.getPath();
if (reportPath.toLowerCase().startsWith("http")) {
ExternalViewerAction.openURL(reportPath);
} else {
String extension = "";
int extPosition = reportPath.lastIndexOf('.');
if (extPosition != -1) {
extension = reportPath.substring(extPosition, reportPath.length()).toLowerCase();
}
ExternalViewerAction.openFile("", extension, new File(reportPath));
}
}
}
}
}

View File

@ -1,180 +0,0 @@
/*
* Autopsy Forensic Browser
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.datamodel;
import java.util.Collection;
import java.util.Collections;
import java.util.logging.Level;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.DerivedFile;
import org.sleuthkit.datamodel.Directory;
import org.sleuthkit.datamodel.File;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.LayoutFile;
import org.sleuthkit.datamodel.LocalDirectory;
import org.sleuthkit.datamodel.LocalFile;
import org.sleuthkit.datamodel.LocalFilesDataSource;
import org.sleuthkit.datamodel.Pool;
import org.sleuthkit.datamodel.SlackFile;
import org.sleuthkit.datamodel.UnsupportedContent;
import org.sleuthkit.datamodel.VirtualDirectory;
import org.sleuthkit.datamodel.Volume;
/**
* Children implementation for the root node of a ContentNode tree. Accepts a
* list of root Content objects for the tree.
*/
public class RootContentChildren extends Children.Keys<Object> {
private static final Logger logger = Logger.getLogger(RootContentChildren.class.getName());
private final Collection<? extends Object> contentKeys;
/**
* @param contentKeys root Content objects for the Node tree
*/
public RootContentChildren(Collection<? extends Object> contentKeys) {
super();
this.contentKeys = contentKeys;
}
@Override
protected void addNotify() {
setKeys(contentKeys);
}
@Override
protected void removeNotify() {
setKeys(Collections.<Object>emptySet());
}
/**
* Refresh all content keys This creates new nodes of keys have changed.
*
* TODO ideally, nodes would respond to event from wrapped content object
* but we are not ready for this.
*/
public void refreshContentKeys() {
contentKeys.forEach(this::refreshKey);
}
@Override
protected Node[] createNodes(Object key) {
Node node = createNode(key);
if (node != null) {
return new Node[]{node};
} else {
logger.log(Level.WARNING, "AbstractContentChildren.CreateTSKNodeVisitor.exception.noNodeMsg");
return new Node[0];
}
}
/**
* Creates a node for one of the known object keys that is not a sleuthkit
* item.
*
* @param key The node key.
*
* @return The generated node or null if no match found.
*/
public static Node createNode(Object key) {
if (key instanceof Tags) {
Tags tagsNodeKey = (Tags) key;
return new Tags.RootNode(tagsNodeKey.filteringDataSourceObjId());
} else if (key instanceof DataSources) {
DataSources dataSourcesKey = (DataSources) key;
return new DataSourceFilesNode(dataSourcesKey.filteringDataSourceObjId());
} else if (key instanceof DataSourceGrouping) {
DataSourceGrouping dataSourceGrouping = (DataSourceGrouping) key;
return new DataSourceGroupingNode(dataSourceGrouping.getDataSource());
} else if (key instanceof Views) {
Views v = (Views) key;
return new ViewsNode(v.filteringDataSourceObjId());
} else if (key instanceof Reports) {
return new Reports.ReportsListNode();
} else if (key instanceof OsAccounts) {
OsAccounts osAccountsItem = (OsAccounts) key;
return osAccountsItem.new OsAccountListNode();
} else if (key instanceof PersonGrouping) {
PersonGrouping personGrouping = (PersonGrouping) key;
return new PersonNode(personGrouping.getPerson());
} else if (key instanceof HostDataSources) {
HostDataSources hosts = (HostDataSources) key;
return new HostNode(hosts);
} else if (key instanceof HostGrouping) {
HostGrouping hostGrouping = (HostGrouping) key;
return new HostNode(hostGrouping);
} else if (key instanceof DataSourcesByType) {
return new DataSourcesNode();
} else if (key instanceof AnalysisResults) {
AnalysisResults analysisResults = (AnalysisResults) key;
return new AnalysisResults.RootNode(
analysisResults.getFilteringDataSourceObjId());
} else if (key instanceof Directory) {
Directory drctr = (Directory) key;
return new DirectoryNode(drctr);
} else if (key instanceof File) {
File file = (File) key;
return new FileNode(file);
} else if (key instanceof Image) {
Image image = (Image) key;
return new ImageNode(image);
} else if (key instanceof Volume) {
Volume volume = (Volume) key;
return new VolumeNode(volume);
} else if (key instanceof Pool) {
Pool pool = (Pool) key;
return new PoolNode(pool);
} else if (key instanceof LayoutFile) {
LayoutFile lf = (LayoutFile) key;
return new LayoutFileNode(lf);
} else if (key instanceof DerivedFile) {
DerivedFile df = (DerivedFile) key;
return new LocalFileNode(df);
} else if (key instanceof LocalFile) {
LocalFile lf = (LocalFile) key;
return new LocalFileNode(lf);
} else if (key instanceof VirtualDirectory) {
VirtualDirectory ld = (VirtualDirectory) key;
return new VirtualDirectoryNode(ld);
} else if (key instanceof LocalDirectory) {
LocalDirectory ld = (LocalDirectory) key;
return new LocalDirectoryNode(ld);
} else if (key instanceof SlackFile) {
SlackFile sf = (SlackFile) key;
return new SlackFileNode(sf);
} else if (key instanceof BlackboardArtifact) {
BlackboardArtifact art = (BlackboardArtifact) key;
return new BlackboardArtifactNode(art);
} else if (key instanceof UnsupportedContent) {
UnsupportedContent uc = (UnsupportedContent) key;
return new UnsupportedContentNode(uc);
} else if (key instanceof LocalFilesDataSource) {
LocalFilesDataSource ld = (LocalFilesDataSource) key;
return new LocalFilesDataSourceNode(ld);
} else if (key instanceof DataArtifacts) {
DataArtifacts dataArtifacts = (DataArtifacts) key;
return new DataArtifacts.RootNode(
dataArtifacts.getFilteringDataSourceObjId());
} else {
return null;
}
}
}

View File

@ -1,49 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 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.datamodel;
import org.sleuthkit.datamodel.SleuthkitCase;
/**
* View nodes support
*/
public class Views {
private SleuthkitCase skCase;
private final long datasourceObjId;
public Views(SleuthkitCase skCase) {
this(skCase, 0);
}
public Views(SleuthkitCase skCase, long dsObjId) {
this.skCase = skCase;
this.datasourceObjId = dsObjId;
}
long filteringDataSourceObjId() {
return this.datasourceObjId;
}
public SleuthkitCase getSleuthkitCase() {
return skCase;
}
}

View File

@ -1,237 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2021 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.datamodel;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import javax.swing.Action;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.BaseChildFactory.NoSuchEventBusException;
import org.sleuthkit.autopsy.directorytree.ExplorerNodeActionVisitor;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.Pool;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.VirtualDirectory;
import org.sleuthkit.datamodel.Volume;
import org.sleuthkit.autopsy.directorytree.FileSystemDetailsAction;
import org.sleuthkit.datamodel.Tag;
/**
* This class is used to represent the "Node" for the volume. Its child is the
* root directory of a file system
*/
public class VolumeNode extends AbstractContentNode<Volume> {
private static final Logger logger = Logger.getLogger(VolumeNode.class.getName());
private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.CONTENT_CHANGED);
/**
* Helper so that the display name and the name used in building the path
* are determined the same way.
*
* @param vol Volume to get the name of
*
* @return short name for the Volume
*/
static String nameForVolume(Volume vol) {
return "vol" + Long.toString(vol.getAddr()); //NON-NLS
}
/**
*
* @param vol underlying Content instance
*/
public VolumeNode(Volume vol) {
super(vol);
// set name, display name, and icon
String volName = nameForVolume(vol);
long end = vol.getStart() + (vol.getLength() - 1);
String tempVolName = volName + " (" + vol.getDescription() + ": " + vol.getStart() + "-" + end + ")";
// If this is a pool volume use a custom display name
try {
if (vol.getParent() != null
&& vol.getParent().getParent() instanceof Pool) {
// Pool volumes are not contiguous so printing a range of blocks is inaccurate
tempVolName = volName + " (" + vol.getDescription() + ": " + vol.getStart() + ")";
}
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Error looking up parent(s) of volume with obj ID = " + vol.getId(), ex);
}
this.setDisplayName(tempVolName);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/vol-icon.png"); //NON-NLS
// Listen for ingest events so that we can detect new added files (e.g. carved)
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
// Listen for case events so that we can detect when case is closed
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
}
private void removeListeners() {
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
}
/*
* This property change listener refreshes the tree when a new file is
* carved out of the unallocated space of this volume.
*/
private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
String eventType = evt.getPropertyName();
// See if the new file is a child of ours
if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) {
if ((evt.getOldValue() instanceof ModuleContentEvent) == false) {
return;
}
ModuleContentEvent moduleContentEvent = (ModuleContentEvent) evt.getOldValue();
if ((moduleContentEvent.getSource() instanceof Content) == false) {
return;
}
Content newContent = (Content) moduleContentEvent.getSource();
try {
Content parent = newContent.getParent();
if (parent != null) {
// Is this a new carved file?
if (parent.getName().equals(VirtualDirectory.NAME_CARVED)) {
// Is this new carved file for this data source?
if (newContent.getDataSource().getId() == getContent().getDataSource().getId()) {
// Find the volume (if any) associated with the new content and
// trigger a refresh if it matches the volume wrapped by this node.
while ((parent = parent.getParent()) != null) {
if (parent.getId() == getContent().getId()) {
BaseChildFactory.post(getName(), new BaseChildFactory.RefreshKeysEvent());
break;
}
}
}
}
}
} catch (TskCoreException ex) {
// Do nothing.
} catch (NoSuchEventBusException ex) {
logger.log(Level.WARNING, eventType, ex);
}
} else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
if (evt.getNewValue() == null) {
// case was closed. Remove listeners so that we don't get called with a stale case handle
removeListeners();
}
}
};
/**
* Right click action for volume node
*
* @param popup
*
* @return
*/
@Override
public Action[] getActions(boolean popup) {
List<Action> actionsList = new ArrayList<>();
actionsList.add(new FileSystemDetailsAction(content));
actionsList.add(new NewWindowViewAction(
NbBundle.getMessage(this.getClass(), "VolumeNode.getActions.viewInNewWin.text"), this));
actionsList.addAll(ExplorerNodeActionVisitor.getActions(content));
actionsList.add(null);
actionsList.addAll(Arrays.asList(super.getActions(true)));
return actionsList.toArray(new Action[actionsList.size()]);
}
@Override
protected Sheet createSheet() {
Sheet sheet = super.createSheet();
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
if (sheetSet == null) {
sheetSet = Sheet.createPropertiesSet();
sheet.put(sheetSet);
}
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "VolumeNode.createSheet.name.name"),
NbBundle.getMessage(this.getClass(), "VolumeNode.createSheet.name.displayName"),
NbBundle.getMessage(this.getClass(), "VolumeNode.createSheet.name.desc"),
this.getDisplayName()));
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "VolumeNode.createSheet.id.name"),
NbBundle.getMessage(this.getClass(), "VolumeNode.createSheet.id.displayName"),
NbBundle.getMessage(this.getClass(), "VolumeNode.createSheet.id.desc"),
content.getAddr()));
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "VolumeNode.createSheet.startSector.name"),
NbBundle.getMessage(this.getClass(), "VolumeNode.createSheet.startSector.displayName"),
NbBundle.getMessage(this.getClass(), "VolumeNode.createSheet.startSector.desc"),
content.getStart()));
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "VolumeNode.createSheet.lenSectors.name"),
NbBundle.getMessage(this.getClass(), "VolumeNode.createSheet.lenSectors.displayName"),
NbBundle.getMessage(this.getClass(), "VolumeNode.createSheet.lenSectors.desc"),
content.getLength()));
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "VolumeNode.createSheet.description.name"),
NbBundle.getMessage(this.getClass(), "VolumeNode.createSheet.description.displayName"),
NbBundle.getMessage(this.getClass(), "VolumeNode.createSheet.description.desc"),
content.getDescription()));
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "VolumeNode.createSheet.flags.name"),
NbBundle.getMessage(this.getClass(), "VolumeNode.createSheet.flags.displayName"),
NbBundle.getMessage(this.getClass(), "VolumeNode.createSheet.flags.desc"),
content.getFlagsAsString()));
return sheet;
}
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
return visitor.visit(this);
}
@Override
public String getItemType() {
return DisplayableItemNode.FILE_PARENT_NODE_KEY;
}
/**
* Reads and returns a list of all tags associated with this content node.
*
* Null implementation of an abstract method.
*
* @return list of tags associated with the node.
*/
@Override
protected List<Tag> getAllTagsFromDatabase() {
return new ArrayList<>();
}
}

View File

@ -48,7 +48,6 @@ import org.sleuthkit.autopsy.commonpropertiessearch.CommonAttributeValueNode;
import org.sleuthkit.autopsy.commonpropertiessearch.CentralRepoCommonAttributeInstanceNode;
import org.sleuthkit.autopsy.datamodel.LocalFileNode;
import org.sleuthkit.autopsy.datamodel.NodeSelectionInfo;
import org.sleuthkit.autopsy.datamodel.Reports;
import org.sleuthkit.autopsy.commonpropertiessearch.CaseDBCommonAttributeInstanceNode;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
@ -246,12 +245,6 @@ public class DataResultFilterNode extends FilterNode {
return Arrays.asList(ban.getActions(true));
}
@Override
public List<Action> visit(Reports.ReportsListNode ditem) {
// The base class Action is "Collapse All", inappropriate.
return null;
}
@Override
protected List<Action> defaultVisit(DisplayableItemNode ditem) {
return Arrays.asList(ditem.getActions(true));
@ -345,11 +338,6 @@ public class DataResultFilterNode extends FilterNode {
}
}
@Override
public AbstractAction visit(Reports.ReportNode reportNode) {
return reportNode.getPreferredAction();
}
@Override
protected AbstractAction defaultVisit(DisplayableItemNode c) {
return openChild(c);

View File

@ -1,338 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 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.util.List;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.openide.nodes.Children;
import org.sleuthkit.autopsy.datamodel.DirectoryNode;
import org.openide.nodes.FilterNode;
import org.openide.nodes.Node;
import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode;
import org.sleuthkit.autopsy.datamodel.AbstractContentNode;
import org.sleuthkit.autopsy.datamodel.AnalysisResults;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
import org.sleuthkit.autopsy.datamodel.DataArtifacts;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
import org.sleuthkit.autopsy.datamodel.FileNode;
import org.sleuthkit.autopsy.datamodel.LayoutFileNode;
import org.sleuthkit.autopsy.datamodel.LocalFileNode;
import org.sleuthkit.autopsy.datamodel.LocalDirectoryNode;
import org.sleuthkit.autopsy.datamodel.SlackFileNode;
import org.sleuthkit.autopsy.datamodel.Tags;
import org.sleuthkit.autopsy.datamodel.ViewsNode;
import org.sleuthkit.autopsy.datamodel.VirtualDirectoryNode;
import org.sleuthkit.autopsy.datamodel.VolumeNode;
import org.sleuthkit.autopsy.mainui.nodes.FileSystemFactory;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.Directory;
import org.sleuthkit.datamodel.LayoutFile;
import org.sleuthkit.datamodel.TskException;
import org.sleuthkit.datamodel.Volume;
/**
* This class wraps around nodes that are displayed in the directory tree and
* hides files, '..', and other children that should not be displayed. facility
* to customize nodes view in dir tree: hide them or set no children
*/
class DirectoryTreeFilterChildren extends FilterNode.Children {
private final ShowItemVisitor showItemV = new ShowItemVisitor();
private final IsLeafItemVisitor isLeafItemV = new IsLeafItemVisitor();
private final static Logger logger = Logger.getLogger(DirectoryTreeFilterChildren.class.getName());
/**
* the constructor
*/
public DirectoryTreeFilterChildren(Node arg) {
super(arg);
}
@Override
protected Node copyNode(Node arg0) {
return new DirectoryTreeFilterNode(arg0, true);
}
protected Node copyNode(Node arg0, boolean createChildren) {
return new DirectoryTreeFilterNode(arg0, createChildren);
}
/*
* This method takes in a node as an argument and will create a new one if
* it should be displayed in the tree. If it is to be displayed, it also
* figures out if it is a leaf or not (i.e. should it have a + sign in the
* tree).
*
* It does NOT create children nodes
*/
@Override
protected Node[] createNodes(Node origNode) {
if (origNode instanceof DataArtifacts.RootNode) {
Node cloned = ((DataArtifacts.RootNode) origNode).clone();
return new Node[]{cloned};
} else if (origNode instanceof AnalysisResults.RootNode) {
Node cloned = ((AnalysisResults.RootNode) origNode).clone();
return new Node[]{cloned};
} else if (origNode instanceof Tags.RootNode) {
Node cloned = ((Tags.RootNode) origNode).clone();
return new Node[]{cloned};
} else if (origNode instanceof ViewsNode) {
Node cloned = ((ViewsNode) origNode).clone();
return new Node[]{cloned};
} else if (origNode instanceof FileSystemFactory.FileSystemTreeNode) {
Node cloned = ((FileSystemFactory.FileSystemTreeNode) origNode).clone();
return new Node[]{cloned};
} else if (origNode == null || !(origNode instanceof DisplayableItemNode)) {
return new Node[]{};
}
// Shoudl this node be displayed in the tree or not
final DisplayableItemNode diNode = (DisplayableItemNode) origNode;
if (diNode.accept(showItemV) == false) {
//do not show
return new Node[]{};
}
// If it is going to be displayed, then determine if it should
// have a '+' next to it based on if it has children of itself.
// We will filter out the "." and ".." directories
final boolean isLeaf = diNode.accept(isLeafItemV);
return new Node[]{this.copyNode(origNode, !isLeaf)};
}
/**
* Don't show expansion button on leaves leaf: all children are (file) or
* (directory named "." or "..")
*
* @param node
*
* @return whether node is a leaf
*/
private static boolean isLeafDirectory(DirectoryNode node) {
Directory dir = node.getLookup().lookup(Directory.class);
boolean ret = true;
try {
for (Content c : dir.getChildren()) {
if (c instanceof Directory && (!((Directory) c).getName().equals(".")
&& !((Directory) c).getName().equals(".."))) {
ret = false;
break;
} else if (AbstractContentNode.contentHasVisibleContentChildren(c)) {
//fie has children, such as derived files
ret = false;
break;
}
}
} catch (TskException ex) {
Logger.getLogger(DirectoryTreeFilterChildren.class.getName())
.log(Level.WARNING, "Error getting directory children", ex); //NON-NLS
return false;
}
return ret;
}
private static boolean isLeafVolume(VolumeNode node) {
Volume vol = node.getLookup().lookup(Volume.class);
boolean ret = true;
try {
for (Content c : vol.getChildren()) {
if (!(c instanceof LayoutFile)) {
ret = false;
break;
}
}
} catch (TskException ex) {
Logger.getLogger(DirectoryTreeFilterChildren.class.getName())
.log(Level.WARNING, "Error getting volume children", ex); //NON-NLS
return false;
}
return ret;
}
/**
* Helper to ignore the '.' and '..' directories
*/
private static boolean isDotDirectory(DirectoryNode dir) {
String name = dir.getDisplayName();
return name.equals(DirectoryNode.DOTDIR) || name.equals(DirectoryNode.DOTDOTDIR);
}
/**
* Return the children based on the current node given. If the node doesn't
* have any directory or volume or image node inside it, it just returns
* leaf.
*
* @param arg the node
*
* @return children the children
*/
public static Children createInstance(Node arg, boolean createChildren) {
if (createChildren) {
return new DirectoryTreeFilterChildren(arg);
} else {
return Children.LEAF;
}
}
private static class IsLeafItemVisitor extends DisplayableItemNodeVisitor.Default<Boolean> {
@Override
protected Boolean defaultVisit(DisplayableItemNode c) {
return c.isLeafTypeNode();
}
@Override
public Boolean visit(DirectoryNode dn) {
return isLeafDirectory(dn);
}
private Boolean visitDeep(AbstractAbstractFileNode<? extends AbstractFile> node) {
//is a leaf if has no children, or children are files not dirs
boolean hasChildren = node.hasContentChildren();
if (!hasChildren) {
return true;
}
List<Content> derivedChildren = node.getContentChildren();
//child of a file, must be a (derived) file too
for (Content childContent : derivedChildren) {
if ((childContent instanceof AbstractFile) && ((AbstractFile) childContent).isDir()) {
return false;
} else {
if (AbstractContentNode.contentHasVisibleContentChildren(childContent)) {
return false;
}
}
}
return true;
}
@Override
public Boolean visit(FileNode fn) {
return visitDeep(fn);
}
@Override
public Boolean visit(LocalFileNode lfn) {
return visitDeep(lfn);
}
@Override
public Boolean visit(LayoutFileNode fn) {
return visitDeep(fn);
}
@Override
public Boolean visit(SlackFileNode sfn) {
return visitDeep(sfn);
}
@Override
public Boolean visit(VolumeNode vn) {
return isLeafVolume(vn);
}
@Override
public Boolean visit(VirtualDirectoryNode vdn) {
return visitDeep(vdn);
}
@Override
public Boolean visit(LocalDirectoryNode ldn) {
return visitDeep(ldn);
}
@Override
public Boolean visit(BlackboardArtifactNode bbafn) {
// Only show Message arttifacts with children
if ((bbafn.getArtifact().getArtifactTypeID() == ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID())
|| (bbafn.getArtifact().getArtifactTypeID() == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID())) {
return bbafn.hasContentChildren();
}
return false;
}
}
private static class ShowItemVisitor extends DisplayableItemNodeVisitor.Default<Boolean> {
@Override
protected Boolean defaultVisit(DisplayableItemNode c) {
return true;
}
@Override
public Boolean visit(DirectoryNode dn) {
if (isDotDirectory(dn)) {
return false;
}
return true;
}
@Override
public Boolean visit(FileNode fn) {
return fn.hasVisibleContentChildren();
}
@Override
public Boolean visit(LocalFileNode lfn) {
return lfn.hasVisibleContentChildren();
}
@Override
public Boolean visit(LayoutFileNode ln) {
return ln.hasVisibleContentChildren();
}
@Override
public Boolean visit(SlackFileNode sfn) {
return sfn.hasVisibleContentChildren();
}
@Override
public Boolean visit(VirtualDirectoryNode vdn) {
return true;
//return vdn.hasContentChildren();
}
@Override
public Boolean visit(LocalDirectoryNode ldn) {
return true;
}
@Override
public Boolean visit(BlackboardArtifactNode bbafn) {
// Only show Message arttifacts with children
if ((bbafn.getArtifact().getArtifactTypeID() == ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID())
|| (bbafn.getArtifact().getArtifactTypeID() == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID())) {
return bbafn.hasContentChildren();
}
return false;
}
}
}

View File

@ -1,200 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 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.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import javax.swing.Action;
import org.openide.nodes.FilterNode;
import org.openide.nodes.Node;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
import org.openide.util.lookup.ProxyLookup;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.AbstractContentNode;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.Host;
import org.sleuthkit.datamodel.Person;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
/**
* A node filter (decorator) that sets the actions for a node in the tree view
* and wraps the Children object of the wrapped node with a
* DirectoryTreeFilterChildren.
*/
class DirectoryTreeFilterNode extends FilterNode {
private static final Logger logger = Logger.getLogger(DirectoryTreeFilterNode.class.getName());
private static final Action collapseAllAction = new CollapseAction(NbBundle.getMessage(DirectoryTreeFilterNode.class, "DirectoryTreeFilterNode.action.collapseAll.text"));
/**
* Constructs node filter (decorator) that sets the actions for a node in
* the tree view and wraps the Children object of the wrapped node with a
* DirectoryTreeFilterChildren.
*
* @param nodeToWrap The node to wrap.
* @param createChildren Whether to create the children of the wrapped node
* or treat it a a leaf node.
*/
DirectoryTreeFilterNode(Node nodeToWrap, boolean createChildren) {
super(nodeToWrap,
DirectoryTreeFilterChildren.createInstance(nodeToWrap, createChildren),
new ProxyLookup(Lookups.singleton(nodeToWrap), nodeToWrap.getLookup()));
}
/**
* Gets the display name for the wrapped node, possibly including a child
* count in parentheses.
*
* @return The display name for the node.
*/
@Override
public String getDisplayName() {
final Node orig = getOriginal();
String name = orig.getDisplayName();
if (orig instanceof AbstractContentNode) {
AbstractFile file = getLookup().lookup(AbstractFile.class);
if ((file != null) && (false == (orig instanceof BlackboardArtifactNode))) {
try {
int numVisibleChildren = getVisibleChildCount(file);
/*
* Left-to-right marks here are necessary to keep the count
* and parens together for mixed right-to-left and
* left-to-right names.
*/
name = name + " \u200E(\u200E" + numVisibleChildren + ")\u200E"; //NON-NLS
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error getting children count to display for file: " + file, ex); //NON-NLS
}
} else if (orig instanceof BlackboardArtifactNode) {
BlackboardArtifact artifact = ((BlackboardArtifactNode) orig).getArtifact();
try {
int numAttachments = artifact.getChildrenCount();
name = name + " \u200E(\u200E" + numAttachments + ")\u200E"; //NON-NLS
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error getting chidlren count for atifact: " + artifact, ex); //NON-NLS
}
}
}
return name;
}
/**
* Gets the number of visible children for a tree view node representing an
* AbstractFile. Depending on the user preferences, known and/or slack files
* will either be included or purged in the count.
*
* @param file The AbstractFile object whose children will be counted.
*
* @return The number of visible children.
*/
private int getVisibleChildCount(AbstractFile file) throws TskCoreException {
List<Content> childList = file.getChildren();
int numVisibleChildren = childList.size();
boolean purgeKnownFiles = UserPreferences.hideKnownFilesInDataSourcesTree();
boolean purgeSlackFiles = UserPreferences.hideSlackFilesInDataSourcesTree();
if (purgeKnownFiles || purgeSlackFiles) {
// Purge known and/or slack files from the file count
for (int i = 0; i < childList.size(); i++) {
Content child = childList.get(i);
if (child instanceof AbstractFile) {
AbstractFile childFile = (AbstractFile) child;
if ((purgeKnownFiles && childFile.getKnown() == TskData.FileKnown.KNOWN)
|| (purgeSlackFiles && childFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.SLACK)) {
numVisibleChildren--;
}
} else if (child instanceof BlackboardArtifact) {
if (FilterNodeUtils.showMessagesInDatasourceTree()) {
// In older versions of Autopsy, attachments were children of email/message artifacts
// and hence email/messages with attachments are shown in the directory tree.
BlackboardArtifact bba = (BlackboardArtifact) child;
// Only message type artifacts are displayed in the tree
if ((bba.getArtifactTypeID() != ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID())
&& (bba.getArtifactTypeID() != ARTIFACT_TYPE.TSK_MESSAGE.getTypeID())) {
numVisibleChildren--;
}
} else {
numVisibleChildren--;
}
}
}
}
return numVisibleChildren;
}
/**
* Gets the context mneu (right click menu) actions for the wrapped node.
*
* @param context Whether to find actions for context meaning or for the
* node itself.
*
* @return
*/
@Override
public Action[] getActions(boolean context) {
List<Action> actions = new ArrayList<>();
actions.addAll(Arrays.asList(getNodeActions()));
if(!this.isLeaf()) {
actions.add(collapseAllAction);
}
return actions.toArray(new Action[actions.size()]);
}
/**
* @return If lookup node is content, host, or person, returns super
* actions. Otherwise, returns empty array.
*/
private Action[] getNodeActions() {
Lookup lookup = this.getLookup();
if (lookup.lookup(Content.class) != null
|| lookup.lookup(Host.class) != null
|| lookup.lookup(Person.class) != null) {
return super.getActions(true);
} else {
return new Action[0];
}
}
/**
* Get the wrapped node.
*
* @return
*/
@Override
public Node getOriginal() {
return super.getOriginal();
}
}

View File

@ -73,14 +73,9 @@ import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
import org.sleuthkit.autopsy.corecomponents.ViewPreferencesPanel;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.autopsy.datamodel.AnalysisResults;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
import org.sleuthkit.autopsy.datamodel.EmptyNode;
import org.sleuthkit.autopsy.datamodel.AutopsyTreeChildFactory;
import org.sleuthkit.autopsy.datamodel.DataArtifacts;
import org.sleuthkit.autopsy.datamodel.OsAccounts;
import org.sleuthkit.autopsy.datamodel.PersonNode;
import org.sleuthkit.autopsy.datamodel.Tags;
import org.sleuthkit.autopsy.datamodel.ViewsNode;
import org.sleuthkit.autopsy.datamodel.accounts.Accounts;
@ -855,13 +850,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
try {
Node treeNode = DirectoryTreeTopComponent.this.getSelectedNode();
if (treeNode != null) {
Node originNode;
if (treeNode instanceof DirectoryTreeFilterNode) {
originNode = ((DirectoryTreeFilterNode) treeNode).getOriginal();
} else {
originNode = treeNode;
}
Node originNode = treeNode;
//set node, wrap in filter node first to filter out children
Node drfn = new DataResultFilterNode(originNode, DirectoryTreeTopComponent.this.em);

View File

@ -22,9 +22,9 @@ import java.util.Objects;
import org.openide.nodes.Node;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.CasePreferences;
import org.sleuthkit.autopsy.datamodel.DataSourceFilesNode;
import org.sleuthkit.autopsy.datamodel.DataSourcesNode;
import static org.sleuthkit.autopsy.directorytree.Bundle.*;
import org.sleuthkit.autopsy.mainui.nodes.RootFactory.AllDataSourcesNode;
import org.sleuthkit.autopsy.mainui.nodes.RootFactory.DataSourceFilesNode;
@NbBundle.Messages({"SelectionContext.dataSources=Data Sources",
"SelectionContext.dataSourceFiles=Data Source Files",
@ -66,7 +66,7 @@ enum SelectionContext {
if (n == null || n.getParentNode() == null) {
// Parent of root node or root node. Occurs during case open / close.
return SelectionContext.OTHER;
} else if ((!Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true) && DataSourcesNode.getNameIdentifier().equals(n.getParentNode().getName()))
} else if ((!Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true) && AllDataSourcesNode.getNameIdentifier().equals(n.getParentNode().getName()))
|| (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true) && DataSourceFilesNode.getNameIdentifier().equals(n.getParentNode().getName()))) {
// if group by data type and root is the DataSourcesNode or
// if group by persons/hosts and parent of DataSourceFilesNode

View File

@ -25,7 +25,6 @@ import org.openide.nodes.Node;
import org.sleuthkit.autopsy.corecomponents.DataContentTopComponent;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
import org.sleuthkit.autopsy.datamodel.RootContentChildren;
import org.sleuthkit.datamodel.Content;
/**

View File

@ -46,11 +46,10 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode;
import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
import org.sleuthkit.autopsy.datamodel.DataSourcesNode;
import org.sleuthkit.autopsy.datamodel.DataSourceFilesNode;
import org.sleuthkit.autopsy.datamodel.PersonNode;
import org.sleuthkit.autopsy.datamodel.RootContentChildren;
import org.sleuthkit.autopsy.mainui.nodes.ChildNodeSelectionInfo.ContentNodeSelectionInfo;
import org.sleuthkit.autopsy.mainui.nodes.RootFactory.AllDataSourcesNode;
import org.sleuthkit.autopsy.mainui.nodes.RootFactory.DataSourceFilesNode;
import org.sleuthkit.autopsy.mainui.nodes.RootFactory.PersonNode;
import org.sleuthkit.autopsy.mainui.nodes.TreeNode;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
@ -242,7 +241,7 @@ public class ViewContextAction extends AbstractAction {
// Classic view
// Start the search at the DataSourcesNode
Children rootChildren = treeViewExplorerMgr.getRootContext().getChildren();
Node rootDsNode = rootChildren == null ? null : rootChildren.findChild(DataSourcesNode.getNameIdentifier());
Node rootDsNode = rootChildren == null ? null : rootChildren.findChild(AllDataSourcesNode.getNameIdentifier());
if (rootDsNode != null) {
for (Node dataSourceLevelNode : getDataSourceLevelNodes(rootDsNode)) {
DataSource dataSource = dataSourceLevelNode.getLookup().lookup(DataSource.class);
@ -383,7 +382,7 @@ public class ViewContextAction extends AbstractAction {
return Collections.emptyList();
} else if (node.getLookup().lookup(Host.class) != null
|| node.getLookup().lookup(Person.class) != null
|| DataSourcesNode.getNameIdentifier().equals(node.getLookup().lookup(String.class))
|| AllDataSourcesNode.getNameIdentifier().equals(node.getLookup().lookup(String.class))
|| PersonNode.getUnknownPersonId().equals(node.getLookup().lookup(String.class))) {
Children children = node.getChildren();
Node[] childNodes = children == null ? null : children.getNodes(true);

View File

@ -111,6 +111,7 @@ public class RootFactory {
}
@Override
@SuppressWarnings("unchecked")
protected Node createNodeForKey(TreeItemDTO<?> key) {
if (key.getSearchParams() instanceof HostSearchParams) {
return new HostNode((TreeItemDTO<? extends HostSearchParams>) key);
@ -140,16 +141,47 @@ public class RootFactory {
@Messages({"RootFactory_AllDataSourcesNode_displayName=Data Sources"})
public static class AllDataSourcesNode extends StaticTreeNode {
private static final String NAME_ID = "ALL_DATA_SOURCES";
/**
* Returns the name identifier of this node.
*
* @return The name identifier.
*/
public static final String getNameIdentifier() {
return NAME_ID;
}
public AllDataSourcesNode() {
super("ALL_DATA_SOURCES",
super(NAME_ID,
Bundle.RootFactory_AllDataSourcesNode_displayName(),
"org/sleuthkit/autopsy/images/image.png",
new AllHostsFactory());
}
}
@Messages(value = {"PersonNode_unknownPersonNode_title=Unknown Persons"})
public static class PersonNode extends TreeNode<PersonSearchParams> {
/**
* Returns the name identifier of this node.
*
* @return The name identifier.
*/
public static final String getNameIdentifier() {
return PersonSearchParams.getTypeId();
}
/**
* Returns the id of an unknown persons node. This can be used with a
* node lookup.
*
* @return The id of an unknown persons node.
*/
public static String getUnknownPersonId() {
return Bundle.PersonNode_unknownPersonNode_title();
}
public PersonNode(TreeResultsDTO.TreeItemDTO<? extends PersonSearchParams> itemData) {
super(PersonSearchParams.getTypeId(),
"org/sleuthkit/autopsy/images/person.png",
@ -249,8 +281,19 @@ public class RootFactory {
@Messages({"RootFactory_DataSourceFilesNode_displayName=Data Source Files"})
public static class DataSourceFilesNode extends StaticTreeNode {
private static final String NAME_ID = "DATA_SOURCE_FILES";
/**
* Returns the name identifier of this node.
*
* @return The name identifier.
*/
public static final String getNameIdentifier() {
return NAME_ID;
}
public DataSourceFilesNode(long dataSourceObjId) {
super("DATA_SOURCE_FILES_" + dataSourceObjId,
super(NAME_ID,
Bundle.RootFactory_DataSourceFilesNode_displayName(),
"org/sleuthkit/autopsy/images/image.png",
new FileSystemFactory(dataSourceObjId));

View File

@ -1,5 +1,5 @@
#Updated by build script
#Tue, 29 Mar 2022 13:48:02 -0400
#Tue, 29 Mar 2022 14:28:23 -0400
LBL_splash_window_title=Starting Autopsy
SPLASH_HEIGHT=314
SPLASH_WIDTH=538

View File

@ -1,4 +1,4 @@
#Updated by build script
#Tue, 29 Mar 2022 13:48:02 -0400
#Tue, 29 Mar 2022 14:28:23 -0400
CTL_MainWindow_Title=Autopsy 4.19.3
CTL_MainWindow_Title_No_Project=Autopsy 4.19.3