This commit is contained in:
Greg DiCristofaro 2022-03-30 10:41:27 -04:00
parent f62aacb779
commit 6e3f4e77a0
11 changed files with 761 additions and 127 deletions

View File

@ -48,6 +48,10 @@ public interface DisplayableItemNodeVisitor<T> {
T visit(FileNode fn);
T visit(ImageNode in);
T visit(VolumeNode vn);
T visit(PoolNode pn);
T visit(SlackFileNode sfn);
@ -56,8 +60,6 @@ public interface DisplayableItemNodeVisitor<T> {
/*
* Views Area
*/
T visit(ViewsNode vn);
T visit(BlackboardArtifactNode ban);
T visit(CommonAttributeValueNode cavn);
@ -85,7 +87,6 @@ public interface DisplayableItemNodeVisitor<T> {
/*
* Reports
*/
T visit(EmptyNode.MessageNode emptyNode);
/*
@ -93,12 +94,12 @@ public interface DisplayableItemNodeVisitor<T> {
*/
T visit(AttachmentNode node);
/*
* Unsupported node
*/
T visit(UnsupportedContentNode ucn);
T visit(LocalFilesDataSourceNode lfdsn);
/**
@ -168,11 +169,21 @@ public interface DisplayableItemNodeVisitor<T> {
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);
@ -188,11 +199,6 @@ public interface DisplayableItemNodeVisitor<T> {
return defaultVisit(ftByMimeTypeEmptyNode);
}
@Override
public T visit(ViewsNode vn) {
return defaultVisit(vn);
}
@Override
public T visit(LayoutFileNode lfn) {
return defaultVisit(lfn);
@ -227,5 +233,10 @@ public interface DisplayableItemNodeVisitor<T> {
public T visit(UnsupportedContentNode node) {
return defaultVisit(node);
}
@Override
public T visit(LocalFilesDataSourceNode node) {
return defaultVisit(node);
}
}
}

View File

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

View File

@ -0,0 +1,94 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.datamodel;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.sleuthkit.datamodel.LocalFilesDataSource;
/**
*
*
*/
public class LocalFilesDataSourceNode extends VirtualDirectoryNode {
private final LocalFilesDataSource localFileDataSource;
public LocalFilesDataSourceNode(LocalFilesDataSource ld) {
super(ld);
localFileDataSource = ld;
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/fileset-icon-16.png"); //NON-NLS
}
@Override
@NbBundle.Messages({"LocalFilesDataSourceNode.createSheet.size.name=Size (Bytes)",
"LocalFilesDataSourceNode.createSheet.size.displayName=Size (Bytes)",
"LocalFilesDataSourceNode.createSheet.size.desc=Size of the data source in bytes.",
"LocalFilesDataSourceNode.createSheet.type.name=Type",
"LocalFilesDataSourceNode.createSheet.type.displayName=Type",
"LocalFilesDataSourceNode.createSheet.type.desc=Type of the image.",
"LocalFilesDataSourceNode.createSheet.type.text=Logical File Set",
"LocalFilesDataSourceNode.createSheet.timezone.name=Timezone",
"LocalFilesDataSourceNode.createSheet.timezone.displayName=Timezone",
"LocalFilesDataSourceNode.createSheet.timezone.desc=Timezone of the image",
"LocalFilesDataSourceNode.createSheet.deviceId.name=Device ID",
"LocalFilesDataSourceNode.createSheet.deviceId.displayName=Device ID",
"LocalFilesDataSourceNode.createSheet.deviceId.desc=Device ID of the image",
"LocalFilesDataSourceNode.createSheet.name.name=Name",
"LocalFilesDataSourceNode.createSheet.name.displayName=Name",
"LocalFilesDataSourceNode.createSheet.name.desc=no description",
"LocalFilesDataSourceNode.createSheet.noDesc=no description",})
protected Sheet createSheet() {
Sheet sheet = new Sheet();
Sheet.Set sheetSet = Sheet.createPropertiesSet();
sheet.put(sheetSet);
sheetSet.put(new NodeProperty<>(Bundle.LocalFilesDataSourceNode_createSheet_name_name(),
Bundle.LocalFilesDataSourceNode_createSheet_name_displayName(),
Bundle.LocalFilesDataSourceNode_createSheet_name_desc(),
getName()));
sheetSet.put(new NodeProperty<>(Bundle.LocalFilesDataSourceNode_createSheet_type_name(),
Bundle.LocalFilesDataSourceNode_createSheet_type_displayName(),
Bundle.LocalFilesDataSourceNode_createSheet_type_desc(),
Bundle.LocalFilesDataSourceNode_createSheet_type_text()));
sheetSet.put(new NodeProperty<>(Bundle.LocalFilesDataSourceNode_createSheet_size_name(),
Bundle.LocalFilesDataSourceNode_createSheet_size_displayName(),
Bundle.LocalFilesDataSourceNode_createSheet_size_desc(),
this.content.getSize()));
sheetSet.put(new NodeProperty<>(Bundle.LocalFilesDataSourceNode_createSheet_timezone_name(),
Bundle.LocalFilesDataSourceNode_createSheet_timezone_displayName(),
Bundle.LocalFilesDataSourceNode_createSheet_timezone_desc(),
""));
sheetSet.put(new NodeProperty<>(Bundle.LocalFilesDataSourceNode_createSheet_deviceId_name(),
Bundle.LocalFilesDataSourceNode_createSheet_deviceId_displayName(),
Bundle.LocalFilesDataSourceNode_createSheet_deviceId_desc(),
localFileDataSource.getDeviceId()));
return sheet;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
return visitor.visit(this);
}
}

View File

@ -1,84 +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 org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.mainui.nodes.ViewsTypeFactory.ViewsChildren;
/**
*
* Node for the views
*
*/
public class ViewsNode extends DisplayableItemNode {
public static final String NAME = NbBundle.getMessage(ViewsNode.class, "ViewsNode.name.text");
private final long dsObjId;
public ViewsNode() {
this(0);
}
public ViewsNode(long dsObjId) {
super(new ViewsChildren(dsObjId > 0 ? dsObjId : null), Lookups.singleton(NAME));
setName(NAME);
setDisplayName(NAME);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/views.png"); //NON-NLS
this.dsObjId = dsObjId;
}
public Node clone() {
return new ViewsNode(dsObjId);
}
@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(), "ViewsNode.createSheet.name.name"),
NbBundle.getMessage(this.getClass(), "ViewsNode.createSheet.name.displayName"),
NbBundle.getMessage(this.getClass(), "ViewsNode.createSheet.name.desc"),
NAME));
return sheet;
}
@Override
public String getItemType() {
return getClass().getName();
}
}

View File

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

View File

@ -77,7 +77,6 @@ import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
import org.sleuthkit.autopsy.datamodel.EmptyNode;
import org.sleuthkit.autopsy.datamodel.Tags;
import org.sleuthkit.autopsy.datamodel.ViewsNode;
import org.sleuthkit.autopsy.datamodel.accounts.Accounts;
import org.sleuthkit.autopsy.corecomponents.SelectionResponder;
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
@ -87,6 +86,11 @@ import org.sleuthkit.autopsy.mainui.datamodel.MainDAO;
import org.sleuthkit.autopsy.mainui.nodes.AnalysisResultTypeFactory.KeywordSetFactory;
import org.sleuthkit.autopsy.mainui.nodes.ChildNodeSelectionInfo.BlackboardArtifactNodeSelectionInfo;
import org.sleuthkit.autopsy.mainui.nodes.RootFactory;
import org.sleuthkit.autopsy.mainui.nodes.RootFactory.AnalysisResultsRootNode;
import org.sleuthkit.autopsy.mainui.nodes.RootFactory.DataArtifactsRootNode;
import org.sleuthkit.autopsy.mainui.nodes.RootFactory.OsAccountsRootNode;
import org.sleuthkit.autopsy.mainui.nodes.RootFactory.PersonNode;
import org.sleuthkit.autopsy.mainui.nodes.RootFactory.ViewsRootNode;
import org.sleuthkit.autopsy.mainui.nodes.TreeNode;
import org.sleuthkit.autopsy.mainui.nodes.ViewsTypeFactory.MimeParentNode;
import org.sleuthkit.datamodel.Account;
@ -126,7 +130,10 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
private static final String SETTINGS_FILE = "CasePreferences.properties"; //NON-NLS
// nodes to be opened if present at top level
private static final Set<String> NODES_TO_EXPAND = Stream.of(AnalysisResults.getName(), DataArtifacts.getName(), ViewsNode.NAME)
private static final Set<String> NODES_TO_EXPAND_PREFIXES = Stream.of(
AnalysisResultsRootNode.getNamePrefix(),
DataArtifactsRootNode.getNamePrefix(),
ViewsRootNode.getNamePrefix())
.collect(Collectors.toSet());
/**
@ -195,7 +202,15 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
.forEach(tree::expandNode);
} else {
Stream.of(rootChildrenNodes)
.filter(n -> n != null && NODES_TO_EXPAND.contains(n.getName()))
.filter(n -> {
// find any where node name is present in prefixes
return n != null
&& n.getName() != null
&& NODES_TO_EXPAND_PREFIXES.stream()
.filter(prefix -> n.getName().startsWith(prefix))
.findAny()
.isPresent();
})
.forEach(tree::expandNode);
}
}
@ -1134,9 +1149,13 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
private Optional<Node> getCategoryNodeChild(Children children, Category category) {
switch (category) {
case DATA_ARTIFACT:
return Optional.ofNullable(children.findChild(DataArtifacts.getName()));
return Stream.of(children.getNodes(true))
.filter(n -> n.getName() != null && n.getName().startsWith(DataArtifactsRootNode.getNamePrefix()))
.findFirst();
case ANALYSIS_RESULT:
return Optional.ofNullable(children.findChild(AnalysisResults.getName()));
return Stream.of(children.getNodes(true))
.filter(n -> n.getName() != null && n.getName().startsWith(AnalysisResultsRootNode.getNamePrefix()))
.findFirst();
default:
LOGGER.log(Level.WARNING, "Unbale to find category of type: " + category.name());
return Optional.empty();
@ -1246,7 +1265,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
}
if (OsAccounts.getListName().equals(node.getName())) {
if (node.getName() != null && node.getName().startsWith(OsAccountsRootNode.getNamePrefix())) {
return Optional.of(node);
}

View File

@ -67,7 +67,9 @@ enum SelectionContext {
// Parent of root node or root node. Occurs during case open / close.
return SelectionContext.OTHER;
} else if ((!Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true) && AllDataSourcesNode.getNameIdentifier().equals(n.getParentNode().getName()))
|| (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true) && DataSourceFilesNode.getNameIdentifier().equals(n.getParentNode().getName()))) {
|| (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)
&& n.getParentNode().getName() != null
&& n.getParentNode().getName().startsWith(DataSourceFilesNode.getNamePrefix()))) {
// if group by data type and root is the DataSourcesNode or
// if group by persons/hosts and parent of DataSourceFilesNode
// then it is a data source node

View File

@ -299,7 +299,14 @@ public class ViewContextAction extends AbstractAction {
}
// for this data source, get the "Data Sources" child node
Node datasourceGroupingNode = treeNode.getChildren().findChild(DataSourceFilesNode.getNameIdentifier());
Node datasourceGroupingNode = Stream.of(treeNode.getChildren().getNodes(true))
.filter(nd -> nd != null && nd.getName() != null && nd.getName().startsWith(DataSourceFilesNode.getNamePrefix()))
.findAny()
.orElse(null);
if (datasourceGroupingNode != null) {
continue;
}
// check whether this is the data source we are looking for
Node parentTreeViewNode = findParentNodeInTree(parentContent, datasourceGroupingNode);

View File

@ -26,7 +26,7 @@ import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.mainui.datamodel.TreeResultsDTO.TreeDisplayCount;
@ -41,8 +41,9 @@ import org.sleuthkit.datamodel.TskCoreException;
/**
*
* Dao for hosts.
* Dao for hosts and persons.
*/
@Messages({"HostPersonDAO_unknownPersons_displayName=Unknown Persons"})
public class HostPersonDAO extends AbstractDAO {
private static HostPersonDAO instance = null;
@ -54,6 +55,10 @@ public class HostPersonDAO extends AbstractDAO {
return instance;
}
public static String getUnknownPersonsName() {
return Bundle.HostPersonDAO_unknownPersons_displayName();
}
private SleuthkitCase getCase() throws NoCurrentCaseException {
return Case.getCurrentCaseThrows().getSleuthkitCase();
}
@ -110,7 +115,7 @@ public class HostPersonDAO extends AbstractDAO {
TreeDisplayCount.NOT_SHOWN);
}
@NbBundle.Messages({"HostPersonDAO_unknownPersons_displayName=Unknown Persons"})
private TreeItemDTO<PersonSearchParams> createPersonTreeItem(Person person) {
return new TreeItemDTO<>(
PersonSearchParams.getTypeId(),

View File

@ -25,7 +25,7 @@ import org.sleuthkit.datamodel.Person;
* Search parameters for a given person.
*/
public class PersonSearchParams {
private static final String TYPE_ID = "Host";
private static final String TYPE_ID = "Person";
public static String getTypeId() {
return TYPE_ID;

View File

@ -31,9 +31,11 @@ import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.util.NbBundle.Messages;
import org.openide.util.WeakListeners;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.CasePreferences;
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.mainui.datamodel.HostPersonDAO;
import org.sleuthkit.autopsy.mainui.datamodel.HostSearchParams;
import org.sleuthkit.autopsy.mainui.datamodel.MainDAO;
import org.sleuthkit.autopsy.mainui.datamodel.OsAccountsSearchParams;
@ -46,7 +48,6 @@ import org.sleuthkit.autopsy.mainui.datamodel.events.DAOEvent;
import org.sleuthkit.autopsy.mainui.datamodel.events.HostPersonEvent;
import org.sleuthkit.autopsy.mainui.datamodel.events.TreeEvent;
import org.sleuthkit.autopsy.mainui.nodes.TreeNode.StaticTreeNode;
import static org.sleuthkit.autopsy.mainui.nodes.TreeNode.getDefaultLookup;
import org.sleuthkit.datamodel.Person;
/**
@ -164,11 +165,11 @@ public class RootFactory {
public static class PersonNode extends TreeNode<PersonSearchParams> {
/**
* Returns the name identifier of this node.
* Returns the name prefix of this node type.
*
* @return The name identifier.
* @return The name prefix.
*/
public static final String getNameIdentifier() {
public static final String getNamePrefix() {
return PersonSearchParams.getTypeId();
}
@ -183,11 +184,16 @@ public class RootFactory {
}
public PersonNode(TreeResultsDTO.TreeItemDTO<? extends PersonSearchParams> itemData) {
super(PersonSearchParams.getTypeId(),
super(PersonSearchParams.getTypeId() + getLongString(
itemData.getSearchParams().getPerson() == null
? 0
: itemData.getSearchParams().getPerson().getPersonId()),
"org/sleuthkit/autopsy/images/person.png",
itemData,
Children.create(new HostFactory(itemData.getSearchParams().getPerson()), true),
getDefaultLookup(itemData));
itemData.getSearchParams().getPerson() != null
? Lookups.fixed(itemData.getSearchParams(), itemData.getSearchParams().getPerson())
: Lookups.fixed(itemData.getSearchParams(), HostPersonDAO.getUnknownPersonsName()));
}
}
@ -243,19 +249,39 @@ public class RootFactory {
public static class HostNode extends TreeNode<HostSearchParams> {
/**
* Returns the name prefix of this node.
*
* @return The name prefix.
*/
public static final String getNamePrefix() {
return HostSearchParams.getTypeId();
}
public HostNode(TreeResultsDTO.TreeItemDTO<? extends HostSearchParams> itemData) {
super(HostSearchParams.getTypeId(),
super(HostSearchParams.getTypeId() + "_" + getLongString(itemData.getSearchParams().getHost().getHostId()),
"org/sleuthkit/autopsy/images/host.png",
itemData,
Children.create(new FileSystemFactory(itemData.getSearchParams().getHost()), true),
getDefaultLookup(itemData));
Lookups.fixed(itemData.getSearchParams(), itemData.getSearchParams().getHost()));
}
}
public static class DataSourceGroupedNode extends StaticTreeNode {
private static final String NAME_PREFIX = "DATA_SOURCE_GROUPED";
/**
* Returns the name prefix of this node.
*
* @return The name prefix.
*/
public static final String getNamePrefix() {
return NAME_PREFIX;
}
public DataSourceGroupedNode(long dataSourceObjId, String dsName, boolean isImage) {
super("DATA_SOURCE_GROUPED_" + dataSourceObjId,
super(NAME_PREFIX + "_" + dataSourceObjId,
dsName,
isImage ? "org/sleuthkit/autopsy/images/image.png" : "org/sleuthkit/autopsy/images/fileset-icon-16.png",
new DataSourceGroupedFactory(dataSourceObjId));
@ -281,19 +307,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";
private static final String NAME_PREFIX = "DATA_SOURCE_FILES";
/**
* Returns the name identifier of this node.
* Returns the name prefix of this node.
*
* @return The name identifier.
* @return The name prefix.
*/
public static final String getNameIdentifier() {
return NAME_ID;
public static final String getNamePrefix() {
return NAME_PREFIX;
}
public DataSourceFilesNode(long dataSourceObjId) {
super(NAME_ID,
super(NAME_PREFIX + "_" + getLongString(dataSourceObjId),
Bundle.RootFactory_DataSourceFilesNode_displayName(),
"org/sleuthkit/autopsy/images/image.png",
new FileSystemFactory(dataSourceObjId));
@ -303,8 +329,19 @@ public class RootFactory {
@Messages({"RootFactory_ViewsRootNode_displayName=Views"})
public static class ViewsRootNode extends StaticTreeNode {
private static final String NAME_PREFIX = "VIEWS";
/**
* Returns the name prefix of this node.
*
* @return The name prefix.
*/
public static final String getNamePrefix() {
return NAME_PREFIX;
}
public ViewsRootNode(Long dataSourceObjId) {
super("VIEWS_" + getLongString(dataSourceObjId),
super(NAME_PREFIX + "_" + getLongString(dataSourceObjId),
Bundle.RootFactory_ViewsRootNode_displayName(),
"org/sleuthkit/autopsy/images/views.png",
new ViewsTypeFactory.ViewsChildren(dataSourceObjId));
@ -314,8 +351,19 @@ public class RootFactory {
@Messages({"RootFactory_DataArtifactsRootNode_displayName=Data Artifacts"})
public static class DataArtifactsRootNode extends StaticTreeNode {
private static final String NAME_PREFIX = "DATA_ARTIFACT";
/**
* Returns the name prefix of this node.
*
* @return The name prefix.
*/
public static final String getNamePrefix() {
return NAME_PREFIX;
}
public DataArtifactsRootNode(Long dataSourceObjId) {
super("DATA_ARTIFACT_" + getLongString(dataSourceObjId),
super(NAME_PREFIX + "_" + getLongString(dataSourceObjId),
Bundle.RootFactory_DataArtifactsRootNode_displayName(),
"org/sleuthkit/autopsy/images/extracted_content.png",
new DataArtifactTypeFactory(dataSourceObjId));
@ -325,8 +373,19 @@ public class RootFactory {
@Messages({"RootFactory_AnalysisResultsRootNode_displayName=Analysis Results"})
public static class AnalysisResultsRootNode extends StaticTreeNode {
private static final String NAME_PREFIX = "DATA_SOURCE_BY_TYPE";
/**
* Returns the name identifier of this node.
*
* @return The name identifier.
*/
public static final String getNamePrefix() {
return NAME_PREFIX;
}
public AnalysisResultsRootNode(Long dataSourceObjId) {
super("DATA_SOURCE_BY_TYPE_" + getLongString(dataSourceObjId),
super(NAME_PREFIX + "_" + getLongString(dataSourceObjId),
Bundle.RootFactory_AnalysisResultsRootNode_displayName(),
"org/sleuthkit/autopsy/images/analysis_result.png",
new AnalysisResultTypeFactory(dataSourceObjId));
@ -336,10 +395,21 @@ public class RootFactory {
@Messages({"RootFactory_OsAccountsRootNode_displayName=OS Accounts"})
public static class OsAccountsRootNode extends StaticTreeNode {
private static final String NAME_PREFIX = "OS_ACCOUNTS";
/**
* Returns the name prefix of this node.
*
* @return The name prefix.
*/
public static final String getNamePrefix() {
return NAME_PREFIX;
}
private final Long dataSourceObjId;
public OsAccountsRootNode(Long dataSourceObjId) {
super("DATA_SOURCE_BY_TYPE_" + getLongString(dataSourceObjId),
super(NAME_PREFIX + "_" + getLongString(dataSourceObjId),
Bundle.RootFactory_OsAccountsRootNode_displayName(),
"org/sleuthkit/autopsy/images/os-account.png");
@ -356,8 +426,19 @@ public class RootFactory {
@Messages({"RootFactory_TagsRootNode_displayName=Tags"})
public static class TagsRootNode extends StaticTreeNode {
private static final String NAME_PREFIX = "DATA_SOURCE_BY_TYPE";
/**
* Returns the name prefix of this node.
*
* @return The name prefix.
*/
public static final String getNamePrefix() {
return NAME_PREFIX;
}
public TagsRootNode(Long dataSourceObjId) {
super("DATA_SOURCE_BY_TYPE_" + getLongString(dataSourceObjId),
super(NAME_PREFIX + "_" + getLongString(dataSourceObjId),
Bundle.RootFactory_TagsRootNode_displayName(),
"org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png",
new TagNameFactory(dataSourceObjId));
@ -367,8 +448,19 @@ public class RootFactory {
@Messages({"RootFactory_ReportsRootNode_displayName=Reports"})
public static class ReportsRootNode extends StaticTreeNode {
private static final String NAME_ID = "REPORTS";
/**
* Returns the name identifier of this node.
*
* @return The name identifier.
*/
public static final String getNameIdentifier() {
return NAME_ID;
}
public ReportsRootNode() {
super("REPORTS",
super(NAME_ID,
Bundle.RootFactory_ReportsRootNode_displayName(),
"org/sleuthkit/autopsy/images/report_16.png");
}