mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-06 21:00:22 +00:00
removing unneeded classes
This commit is contained in:
parent
441a9c6f23
commit
721fc11c48
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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 {
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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()]);
|
||||
}
|
||||
}
|
@ -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<>();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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<>();
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user