commenting

This commit is contained in:
Greg DiCristofaro 2022-03-31 11:46:26 -04:00
parent e8995a18b4
commit b5faa7cea7
11 changed files with 453 additions and 48 deletions

View File

@ -1312,7 +1312,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
Node osAccountListNode = osAccountListNodeOpt.get(); Node osAccountListNode = osAccountListNodeOpt.get();
if (osAccountListNode instanceof TreeNode) { if (osAccountListNode instanceof TreeNode) {
TreeNode treeNode = (TreeNode) osAccountListNode; TreeNode<?> treeNode = (TreeNode<?>) osAccountListNode;
treeNode.setNodeSelectionInfo(new OsAccountNodeSelectionInfo(osAccount.getId())); treeNode.setNodeSelectionInfo(new OsAccountNodeSelectionInfo(osAccount.getId()));
} }

View File

@ -48,13 +48,19 @@ public class HostPersonDAO extends AbstractDAO {
private static HostPersonDAO instance = null; private static HostPersonDAO instance = null;
/**
* @return The singleton instance of this class.
*/
public static HostPersonDAO getInstance() { public static HostPersonDAO getInstance() {
if (instance == null) { if (instance == null) {
instance = new HostPersonDAO(); instance = new HostPersonDAO();
} }
return instance; return instance;
} }
/**
* @return Identifier used for unknown persons.
*/
public static String getUnknownPersonsName() { public static String getUnknownPersonsName() {
return Bundle.HostPersonDAO_unknownPersons_displayName(); return Bundle.HostPersonDAO_unknownPersons_displayName();
} }
@ -63,6 +69,13 @@ public class HostPersonDAO extends AbstractDAO {
return Case.getCurrentCaseThrows().getSleuthkitCase(); return Case.getCurrentCaseThrows().getSleuthkitCase();
} }
/**
* Returns tree items for all hosts in the case.
*
* @return All hosts in the case.
*
* @throws ExecutionException
*/
public TreeResultsDTO<HostSearchParams> getAllHosts() throws ExecutionException { public TreeResultsDTO<HostSearchParams> getAllHosts() throws ExecutionException {
try { try {
return new TreeResultsDTO<>(getCase().getHostManager().getAllHosts().stream() return new TreeResultsDTO<>(getCase().getHostManager().getAllHosts().stream()
@ -73,12 +86,23 @@ public class HostPersonDAO extends AbstractDAO {
} }
} }
/**
* Queries for all hosts belonging to the person or all hosts without a
* person association if person parameter is null.
*
* @param person The person to which hosts belong to or null for hosts with
* no associated person.
*
* @return The results in tree item form.
*
* @throws ExecutionException
*/
public TreeResultsDTO<HostSearchParams> getHosts(Person person) throws ExecutionException { public TreeResultsDTO<HostSearchParams> getHosts(Person person) throws ExecutionException {
try { try {
List<Host> hosts = person == null List<Host> hosts = person == null
? getCase().getPersonManager().getHostsWithoutPersons() ? getCase().getPersonManager().getHostsWithoutPersons()
: getCase().getPersonManager().getHostsForPerson(person); : getCase().getPersonManager().getHostsForPerson(person);
return new TreeResultsDTO<>(hosts.stream() return new TreeResultsDTO<>(hosts.stream()
.map(h -> createHostTreeItem(h)) .map(h -> createHostTreeItem(h))
.collect(Collectors.toList())); .collect(Collectors.toList()));
@ -87,19 +111,24 @@ public class HostPersonDAO extends AbstractDAO {
} }
} }
/**
* Returns all persons associated with the case.
* @return The person tree results.
* @throws ExecutionException
*/
public TreeResultsDTO<PersonSearchParams> getAllPersons() throws ExecutionException { public TreeResultsDTO<PersonSearchParams> getAllPersons() throws ExecutionException {
try { try {
List<Person> persons = getCase().getPersonManager().getPersons(); List<Person> persons = getCase().getPersonManager().getPersons();
List<TreeItemDTO<PersonSearchParams>> personSearchParams = new ArrayList<>(); List<TreeItemDTO<PersonSearchParams>> personSearchParams = new ArrayList<>();
for (Person person : persons) { for (Person person : persons) {
personSearchParams.add(createPersonTreeItem(person)); personSearchParams.add(createPersonTreeItem(person));
} }
if (!getCase().getPersonManager().getHostsWithoutPersons().isEmpty()) { if (!getCase().getPersonManager().getHostsWithoutPersons().isEmpty()) {
personSearchParams.add(createPersonTreeItem(null)); personSearchParams.add(createPersonTreeItem(null));
} }
return new TreeResultsDTO<>(personSearchParams); return new TreeResultsDTO<>(personSearchParams);
} catch (TskCoreException | NoCurrentCaseException ex) { } catch (TskCoreException | NoCurrentCaseException ex) {
throw new ExecutionException("Error while fetching all hosts.", ex); throw new ExecutionException("Error while fetching all hosts.", ex);
@ -115,7 +144,6 @@ public class HostPersonDAO extends AbstractDAO {
TreeDisplayCount.NOT_SHOWN); TreeDisplayCount.NOT_SHOWN);
} }
private TreeItemDTO<PersonSearchParams> createPersonTreeItem(Person person) { private TreeItemDTO<PersonSearchParams> createPersonTreeItem(Person person) {
return new TreeItemDTO<>( return new TreeItemDTO<>(
PersonSearchParams.getTypeId(), PersonSearchParams.getTypeId(),
@ -138,10 +166,9 @@ public class HostPersonDAO extends AbstractDAO {
.map(caseEvent -> caseEvent.toString()) .map(caseEvent -> caseEvent.toString())
.collect(Collectors.toSet()); .collect(Collectors.toSet());
@Override @Override
Set<? extends DAOEvent> processEvent(PropertyChangeEvent evt) { Set<? extends DAOEvent> processEvent(PropertyChangeEvent evt) {
return caseEvents.contains(evt.getPropertyName()) return caseEvents.contains(evt.getPropertyName())
? Collections.singleton(new HostPersonEvent()) ? Collections.singleton(new HostPersonEvent())
: Collections.emptySet(); : Collections.emptySet();
} }

View File

@ -33,10 +33,17 @@ public class HostSearchParams {
private final Host host; private final Host host;
/**
* Main constructor.
* @param host The host.
*/
public HostSearchParams(Host host) { public HostSearchParams(Host host) {
this.host = host; this.host = host;
} }
/**
* @return The host.
*/
public Host getHost() { public Host getHost() {
return host; return host;
} }

View File

@ -48,6 +48,9 @@ public class ReportsDAO extends AbstractDAO {
private static ReportsDAO instance = null; private static ReportsDAO instance = null;
/**
* @return A singleton instance of this class.
*/
public static ReportsDAO getInstance() { public static ReportsDAO getInstance() {
if (instance == null) { if (instance == null) {
instance = new ReportsDAO(); instance = new ReportsDAO();
@ -57,6 +60,7 @@ public class ReportsDAO extends AbstractDAO {
private final Cache<SearchParams<ReportsSearchParams>, SearchResultsDTO> cache = CacheBuilder.newBuilder().maximumSize(CACHE_SIZE).expireAfterAccess(CACHE_DURATION, CACHE_DURATION_UNITS).build(); private final Cache<SearchParams<ReportsSearchParams>, SearchResultsDTO> cache = CacheBuilder.newBuilder().maximumSize(CACHE_SIZE).expireAfterAccess(CACHE_DURATION, CACHE_DURATION_UNITS).build();
private SleuthkitCase getCase() throws NoCurrentCaseException { private SleuthkitCase getCase() throws NoCurrentCaseException {
return Case.getCurrentCaseThrows().getSleuthkitCase(); return Case.getCurrentCaseThrows().getSleuthkitCase();
} }
@ -97,6 +101,15 @@ public class ReportsDAO extends AbstractDAO {
totalResultCount); totalResultCount);
} }
/**
* Queries the case based on the report search params and returns search results.
* @param repSearchParams The report search params.
* @param startItem The paged starting item.
* @param maxResultsCount The maximum result count for the page.
* @return The search results.
* @throws ExecutionException
* @throws IllegalArgumentException
*/
public SearchResultsDTO getReports(ReportsSearchParams repSearchParams, long startItem, Long maxResultsCount) throws ExecutionException, IllegalArgumentException { public SearchResultsDTO getReports(ReportsSearchParams repSearchParams, long startItem, Long maxResultsCount) throws ExecutionException, IllegalArgumentException {
SearchParams<ReportsSearchParams> searchParams = new SearchParams<>(repSearchParams, startItem, maxResultsCount); SearchParams<ReportsSearchParams> searchParams = new SearchParams<>(repSearchParams, startItem, maxResultsCount);
return cache.get(searchParams, () -> fetchReports(searchParams)); return cache.get(searchParams, () -> fetchReports(searchParams));

View File

@ -51,6 +51,9 @@ public class ReportsRowDTO extends BaseRowDTO {
private static final String TYPE_ID = "REPORTS"; private static final String TYPE_ID = "REPORTS";
/**
* @return The type identifier of this class.
*/
public static String getTypeIdForClass() { public static String getTypeIdForClass() {
return TYPE_ID; return TYPE_ID;
} }
@ -61,6 +64,15 @@ public class ReportsRowDTO extends BaseRowDTO {
private final String reportFilePath; private final String reportFilePath;
private final Report report; private final Report report;
/**
* Main constructor.
* @param report The report.
* @param id The report id.
* @param sourceModuleName The source module name.
* @param reportName The report name.
* @param createdTime The created time.
* @param reportFilePath The report file path.
*/
public ReportsRowDTO(Report report, long id, String sourceModuleName, String reportName, Date createdTime, String reportFilePath) { public ReportsRowDTO(Report report, long id, String sourceModuleName, String reportName, Date createdTime, String reportFilePath) {
super(ImmutableList.of(sourceModuleName, reportName, createdTime, reportFilePath), TYPE_ID, id); super(ImmutableList.of(sourceModuleName, reportName, createdTime, reportFilePath), TYPE_ID, id);
this.sourceModuleName = sourceModuleName; this.sourceModuleName = sourceModuleName;
@ -70,22 +82,37 @@ public class ReportsRowDTO extends BaseRowDTO {
this.report = report; this.report = report;
} }
/**
* @return The source module name.
*/
public String getSourceModuleName() { public String getSourceModuleName() {
return sourceModuleName; return sourceModuleName;
} }
/**
* @return The report name.
*/
public String getReportName() { public String getReportName() {
return reportName; return reportName;
} }
/**
* @return The created time.
*/
public Date getCreatedTime() { public Date getCreatedTime() {
return createdTime; return createdTime;
} }
/**
* @return The report file path.
*/
public String getReportFilePath() { public String getReportFilePath() {
return reportFilePath; return reportFilePath;
} }
/**
* @return The report.
*/
public Report getReport() { public Report getReport() {
return report; return report;
} }

View File

@ -36,6 +36,9 @@ public class ReportsSearchParams {
private static ReportsSearchParams instance = null; private static ReportsSearchParams instance = null;
/**
* @return A singleton instance of this class.
*/
public static ReportsSearchParams getInstance() { public static ReportsSearchParams getInstance() {
if (instance == null) { if (instance == null) {
instance = new ReportsSearchParams(); instance = new ReportsSearchParams();

View File

@ -75,10 +75,17 @@ public interface ChildNodeSelectionInfo {
} }
} }
/**
* The selection of an os account.
*/
public class OsAccountNodeSelectionInfo implements ChildNodeSelectionInfo { public class OsAccountNodeSelectionInfo implements ChildNodeSelectionInfo {
private final long osAccountId; private final long osAccountId;
/**
* Main constructor.
* @param osAccountId The os account id.
*/
public OsAccountNodeSelectionInfo(long osAccountId) { public OsAccountNodeSelectionInfo(long osAccountId) {
this.osAccountId = osAccountId; this.osAccountId = osAccountId;
} }

View File

@ -20,7 +20,6 @@ package org.sleuthkit.autopsy.mainui.nodes;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.util.Collections;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import org.openide.nodes.Children; import org.openide.nodes.Children;
@ -28,7 +27,6 @@ import org.openide.nodes.Node;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.logging.Level; import java.util.logging.Level;
import javax.swing.Action; import javax.swing.Action;
import javax.swing.SwingUtilities;
import org.openide.util.Lookup; import org.openide.util.Lookup;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
@ -37,7 +35,6 @@ import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.FileTypeExtensions; import org.sleuthkit.autopsy.datamodel.FileTypeExtensions;
import org.sleuthkit.autopsy.datamodel.NodeProperty;
import org.sleuthkit.autopsy.datamodel.utils.FileNameTransTask; import org.sleuthkit.autopsy.datamodel.utils.FileNameTransTask;
import org.sleuthkit.autopsy.directorytree.ExtractUnallocAction; import org.sleuthkit.autopsy.directorytree.ExtractUnallocAction;
import org.sleuthkit.autopsy.directorytree.FileSystemDetailsAction; import org.sleuthkit.autopsy.directorytree.FileSystemDetailsAction;
@ -55,7 +52,6 @@ import static org.sleuthkit.autopsy.mainui.nodes.NodeIconUtil.DELETED_FILE;
import static org.sleuthkit.autopsy.mainui.nodes.NodeIconUtil.DELETED_FOLDER; import static org.sleuthkit.autopsy.mainui.nodes.NodeIconUtil.DELETED_FOLDER;
import static org.sleuthkit.autopsy.mainui.nodes.NodeIconUtil.FOLDER; import static org.sleuthkit.autopsy.mainui.nodes.NodeIconUtil.FOLDER;
import static org.sleuthkit.autopsy.mainui.nodes.TreeNode.getDefaultLookup; import static org.sleuthkit.autopsy.mainui.nodes.TreeNode.getDefaultLookup;
import org.sleuthkit.autopsy.mainui.nodes.actions.ActionContext;
import org.sleuthkit.autopsy.mainui.nodes.actions.ActionsFactory; import org.sleuthkit.autopsy.mainui.nodes.actions.ActionsFactory;
import org.sleuthkit.autopsy.texttranslation.TextTranslationService; import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;

View File

@ -24,17 +24,23 @@ import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.logging.Level; import java.util.logging.Level;
import org.openide.nodes.ChildFactory; import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children; import org.openide.nodes.Children;
import org.openide.nodes.Node; import org.openide.nodes.Node;
import org.openide.util.Lookup;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.openide.util.WeakListeners; import org.openide.util.WeakListeners;
import org.openide.util.lookup.Lookups; import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.CasePreferences; import org.sleuthkit.autopsy.casemodule.CasePreferences;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.mainui.datamodel.FileSystemContentSearchParam;
import org.sleuthkit.autopsy.mainui.datamodel.FileSystemDAO;
import org.sleuthkit.autopsy.mainui.datamodel.HostPersonDAO; import org.sleuthkit.autopsy.mainui.datamodel.HostPersonDAO;
import org.sleuthkit.autopsy.mainui.datamodel.HostSearchParams; import org.sleuthkit.autopsy.mainui.datamodel.HostSearchParams;
import org.sleuthkit.autopsy.mainui.datamodel.MainDAO; import org.sleuthkit.autopsy.mainui.datamodel.MainDAO;
@ -48,7 +54,13 @@ import org.sleuthkit.autopsy.mainui.datamodel.events.DAOEvent;
import org.sleuthkit.autopsy.mainui.datamodel.events.HostPersonEvent; import org.sleuthkit.autopsy.mainui.datamodel.events.HostPersonEvent;
import org.sleuthkit.autopsy.mainui.datamodel.events.TreeEvent; import org.sleuthkit.autopsy.mainui.datamodel.events.TreeEvent;
import org.sleuthkit.autopsy.mainui.nodes.TreeNode.StaticTreeNode; import org.sleuthkit.autopsy.mainui.nodes.TreeNode.StaticTreeNode;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.Host;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.LocalFilesDataSource;
import org.sleuthkit.datamodel.Person; import org.sleuthkit.datamodel.Person;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskDataException;
/** /**
* *
@ -56,14 +68,24 @@ import org.sleuthkit.datamodel.Person;
*/ */
public class RootFactory { public class RootFactory {
/**
* @return The root children to be displayed in the tree.
*/
public static Children getRootChildren() { public static Children getRootChildren() {
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) { if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
return Children.create(new HostPersonRootFactory(), true); return Children.create(new HostPersonRootFactory(), true);
} else { } else {
return new DefaultViewRootFactory(); return new DefaultViewRootChildren();
} }
} }
/**
* Returns a string of the safely converted long to be used in a name id.
*
* @param l The number or null.
*
* @return The safely stringified number.
*/
private static String getLongString(Long l) { private static String getLongString(Long l) {
return l == null ? "" : l.toString(); return l == null ? "" : l.toString();
} }
@ -115,7 +137,7 @@ public class RootFactory {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected Node createNodeForKey(TreeItemDTO<?> key) { protected Node createNodeForKey(TreeItemDTO<?> key) {
if (key.getSearchParams() instanceof HostSearchParams) { if (key.getSearchParams() instanceof HostSearchParams) {
return new HostNode((TreeItemDTO<? extends HostSearchParams>) key); return HostNode.getPersonHostViewNode((TreeItemDTO<? extends HostSearchParams>) key);
} else if (key.getSearchParams() instanceof PersonSearchParams) { } else if (key.getSearchParams() instanceof PersonSearchParams) {
return new PersonNode((TreeItemDTO<? extends PersonSearchParams>) key); return new PersonNode((TreeItemDTO<? extends PersonSearchParams>) key);
} else { } else {
@ -124,9 +146,15 @@ public class RootFactory {
} }
} }
public static class DefaultViewRootFactory extends Children.Array { /**
* The root children for the default view preference.
*/
public static class DefaultViewRootChildren extends Children.Array {
public DefaultViewRootFactory() { /**
* Main constructor.
*/
public DefaultViewRootChildren() {
super(Arrays.asList( super(Arrays.asList(
new AllDataSourcesNode(), new AllDataSourcesNode(),
new ViewsRootNode(null), new ViewsRootNode(null),
@ -139,6 +167,9 @@ public class RootFactory {
} }
} }
/**
* Node in default view displaying all hosts/data sources.
*/
@Messages({"RootFactory_AllDataSourcesNode_displayName=Data Sources"}) @Messages({"RootFactory_AllDataSourcesNode_displayName=Data Sources"})
public static class AllDataSourcesNode extends StaticTreeNode { public static class AllDataSourcesNode extends StaticTreeNode {
@ -153,6 +184,9 @@ public class RootFactory {
return NAME_ID; return NAME_ID;
} }
/**
* Main constructor.
*/
public AllDataSourcesNode() { public AllDataSourcesNode() {
super(NAME_ID, super(NAME_ID,
Bundle.RootFactory_AllDataSourcesNode_displayName(), Bundle.RootFactory_AllDataSourcesNode_displayName(),
@ -161,6 +195,9 @@ public class RootFactory {
} }
} }
/**
* A person node.
*/
@Messages(value = {"PersonNode_unknownPersonNode_title=Unknown Persons"}) @Messages(value = {"PersonNode_unknownPersonNode_title=Unknown Persons"})
public static class PersonNode extends TreeNode<PersonSearchParams> { public static class PersonNode extends TreeNode<PersonSearchParams> {
@ -183,11 +220,16 @@ public class RootFactory {
return Bundle.PersonNode_unknownPersonNode_title(); return Bundle.PersonNode_unknownPersonNode_title();
} }
/**
* Main constructor.
*
* @param itemData The row data for the person.
*/
public PersonNode(TreeResultsDTO.TreeItemDTO<? extends PersonSearchParams> itemData) { public PersonNode(TreeResultsDTO.TreeItemDTO<? extends PersonSearchParams> itemData) {
super(PersonSearchParams.getTypeId() + getLongString( super(PersonSearchParams.getTypeId() + getLongString(
itemData.getSearchParams().getPerson() == null itemData.getSearchParams().getPerson() == null
? 0 ? 0
: itemData.getSearchParams().getPerson().getPersonId()), : itemData.getSearchParams().getPerson().getPersonId()),
"org/sleuthkit/autopsy/images/person.png", "org/sleuthkit/autopsy/images/person.png",
itemData, itemData,
Children.create(new HostFactory(itemData.getSearchParams().getPerson()), true), Children.create(new HostFactory(itemData.getSearchParams().getPerson()), true),
@ -195,20 +237,43 @@ public class RootFactory {
? Lookups.fixed(itemData.getSearchParams(), itemData.getSearchParams().getPerson()) ? Lookups.fixed(itemData.getSearchParams(), itemData.getSearchParams().getPerson())
: Lookups.fixed(itemData.getSearchParams(), HostPersonDAO.getUnknownPersonsName())); : Lookups.fixed(itemData.getSearchParams(), HostPersonDAO.getUnknownPersonsName()));
} }
@Override
public Optional<Person> getPerson() {
return Optional.of(getItemData().getSearchParams().getPerson());
}
} }
/**
* Factory displaying all hosts in default view.
*/
public static class AllHostsFactory extends BaseHostFactory { public static class AllHostsFactory extends BaseHostFactory {
@Override @Override
protected TreeResultsDTO<? extends HostSearchParams> getChildResults() throws IllegalArgumentException, ExecutionException { protected TreeResultsDTO<? extends HostSearchParams> getChildResults() throws IllegalArgumentException, ExecutionException {
return MainDAO.getInstance().getHostPersonDAO().getAllHosts(); return MainDAO.getInstance().getHostPersonDAO().getAllHosts();
} }
@Override
protected TreeNode<HostSearchParams> createNewNode(TreeItemDTO<? extends HostSearchParams> rowData) {
return HostNode.getDefaultViewNode(rowData);
}
} }
/**
* Factory displaying hosts belonging to a person (or null).
*/
public static class HostFactory extends BaseHostFactory { public static class HostFactory extends BaseHostFactory {
private final Person parentPerson; private final Person parentPerson;
/**
* Main constructor.
*
* @param parentPerson The person whose hosts will be shown. Null
* indicates showing any host with no person
* associated.
*/
public HostFactory(Person parentPerson) { public HostFactory(Person parentPerson) {
this.parentPerson = parentPerson; this.parentPerson = parentPerson;
} }
@ -217,14 +282,17 @@ public class RootFactory {
protected TreeResultsDTO<? extends HostSearchParams> getChildResults() throws IllegalArgumentException, ExecutionException { protected TreeResultsDTO<? extends HostSearchParams> getChildResults() throws IllegalArgumentException, ExecutionException {
return MainDAO.getInstance().getHostPersonDAO().getHosts(parentPerson); return MainDAO.getInstance().getHostPersonDAO().getHosts(parentPerson);
} }
}
public abstract static class BaseHostFactory extends TreeChildFactory<HostSearchParams> {
@Override @Override
protected TreeNode<HostSearchParams> createNewNode(TreeResultsDTO.TreeItemDTO<? extends HostSearchParams> rowData) { protected TreeNode<HostSearchParams> createNewNode(TreeItemDTO<? extends HostSearchParams> rowData) {
return new HostNode(rowData); return HostNode.getPersonHostViewNode(rowData);
} }
}
/**
* Base factory for displaying hosts.
*/
public abstract static class BaseHostFactory extends TreeChildFactory<HostSearchParams> {
@Override @Override
protected void handleDAOAggregateEvent(DAOAggregateEvent aggEvt) { protected void handleDAOAggregateEvent(DAOAggregateEvent aggEvt) {
@ -247,8 +315,11 @@ public class RootFactory {
} }
} }
/**
* Node for a host.
*/
public static class HostNode extends TreeNode<HostSearchParams> { public static class HostNode extends TreeNode<HostSearchParams> {
/** /**
* Returns the name prefix of this node. * Returns the name prefix of this node.
* *
@ -257,17 +328,78 @@ public class RootFactory {
public static final String getNamePrefix() { public static final String getNamePrefix() {
return HostSearchParams.getTypeId(); return HostSearchParams.getTypeId();
} }
public HostNode(TreeResultsDTO.TreeItemDTO<? extends HostSearchParams> itemData) { /**
* Returns a host node whose children will be used in the default view.
*
* @param itemData The data associated with the host.
*
* @return A host node.
*/
public static HostNode getDefaultViewNode(TreeResultsDTO.TreeItemDTO<? extends HostSearchParams> itemData) {
return new HostNode(itemData, Children.create(new FileSystemFactory(itemData.getSearchParams().getHost()), true));
}
/**
* Returns a host node whose children will be used in the person/host
* view.
*
* @param itemData The data associated with the host.
*
* @return A host node.
*/
public static HostNode getPersonHostViewNode(TreeResultsDTO.TreeItemDTO<? extends HostSearchParams> itemData) {
return new HostNode(itemData, Children.create(new FileSystemFactory(itemData.getSearchParams().getHost()), true));
}
/**
* Private constructor.
*
* @param itemData The data for the host.
* @param children The children to use with this host.
*/
private HostNode(TreeResultsDTO.TreeItemDTO<? extends HostSearchParams> itemData, Children children) {
super(HostSearchParams.getTypeId() + "_" + getLongString(itemData.getSearchParams().getHost().getHostId()), super(HostSearchParams.getTypeId() + "_" + getLongString(itemData.getSearchParams().getHost().getHostId()),
"org/sleuthkit/autopsy/images/host.png", "org/sleuthkit/autopsy/images/host.png",
itemData, itemData,
Children.create(new FileSystemFactory(itemData.getSearchParams().getHost()), true), children,
Lookups.fixed(itemData.getSearchParams(), itemData.getSearchParams().getHost())); Lookups.fixed(itemData.getSearchParams(), itemData.getSearchParams().getHost()));
} }
@Override
public Optional<Host> getHost() {
return Optional.of(getItemData().getSearchParams().getHost());
}
} }
public static class DataSourceGroupedNode extends StaticTreeNode { /**
* The factory to use to create data source grouping nodes to display in the
* host/person view.
*/
public static class DataSourceGroupedFactory extends FileSystemFactory {
/**
* Main constructor.
*
* @param host The parent host.
*/
public DataSourceGroupedFactory(Host host) {
super(host);
}
@Override
protected TreeNode<FileSystemContentSearchParam> createNewNode(TreeItemDTO<? extends FileSystemContentSearchParam> rowData) {
return DataSourceGroupedNode.getInstance(rowData);
}
}
/**
* A data source grouping node to display in host/person view.
*/
public static class DataSourceGroupedNode extends TreeNode<FileSystemContentSearchParam> {
private static final Logger logger = Logger.getLogger(DataSourceGroupedNode.class.getName());
private static final String NAME_PREFIX = "DATA_SOURCE_GROUPED"; private static final String NAME_PREFIX = "DATA_SOURCE_GROUPED";
@ -279,19 +411,57 @@ public class RootFactory {
public static final String getNamePrefix() { public static final String getNamePrefix() {
return NAME_PREFIX; return NAME_PREFIX;
} }
public DataSourceGroupedNode(long dataSourceObjId, String dsName, boolean isImage) { /**
super(NAME_PREFIX + "_" + dataSourceObjId, * Returns an instance of the data source grouping node.
dsName, *
isImage ? "org/sleuthkit/autopsy/images/image.png" : "org/sleuthkit/autopsy/images/fileset-icon-16.png", * @param itemData The row data.
new DataSourceGroupedFactory(dataSourceObjId)); *
* @return The node.
*/
public static DataSourceGroupedNode getInstance(TreeItemDTO<? extends FileSystemContentSearchParam> itemData) {
long dataSourceId = itemData.getSearchParams().getContentObjectId();
try {
DataSource ds = Case.getCurrentCaseThrows().getSleuthkitCase().getDataSource(dataSourceId);
return (ds == null) ? null : new DataSourceGroupedNode(itemData, ds);
} catch (NoCurrentCaseException ex) {
// Case is likely closing
return null;
} catch (TskCoreException | TskDataException ex) {
logger.log(Level.SEVERE, "Error creating node from data source with ID: " + dataSourceId, ex);
return null;
}
}
/**
* Private constructor.
*
* @param itemData The row data.
* @param dataSource The relevant data source instance.
*/
private DataSourceGroupedNode(TreeItemDTO<? extends FileSystemContentSearchParam> itemData, DataSource dataSource) {
super(NAME_PREFIX + "_" + getLongString(dataSource.getId()),
dataSource instanceof Image
? "org/sleuthkit/autopsy/images/image.png"
: "org/sleuthkit/autopsy/images/fileset-icon-16.png",
itemData,
new DataSourceGroupedChildren(dataSource.getId()),
Lookups.singleton(dataSource));
} }
} }
// shows all content related to data sources /**
public static class DataSourceGroupedFactory extends Children.Array { * Shows all content related to a data source in host/person view.
*/
public static class DataSourceGroupedChildren extends Children.Array {
public DataSourceGroupedFactory(long dataSourceObjId) { /**
* Main constructor.
*
* @param dataSourceObjId The data source object id.
*/
public DataSourceGroupedChildren(long dataSourceObjId) {
super(Arrays.asList( super(Arrays.asList(
new DataSourceFilesNode(dataSourceObjId), new DataSourceFilesNode(dataSourceObjId),
new ViewsRootNode(dataSourceObjId), new ViewsRootNode(dataSourceObjId),
@ -304,6 +474,9 @@ public class RootFactory {
} }
} }
/**
* Node for showing data source files in person/host view.
*/
@Messages({"RootFactory_DataSourceFilesNode_displayName=Data Source Files"}) @Messages({"RootFactory_DataSourceFilesNode_displayName=Data Source Files"})
public static class DataSourceFilesNode extends StaticTreeNode { public static class DataSourceFilesNode extends StaticTreeNode {
@ -317,7 +490,12 @@ public class RootFactory {
public static final String getNamePrefix() { public static final String getNamePrefix() {
return NAME_PREFIX; return NAME_PREFIX;
} }
/**
* Main constructor.
*
* @param dataSourceObjId The data source object id.
*/
public DataSourceFilesNode(long dataSourceObjId) { public DataSourceFilesNode(long dataSourceObjId) {
super(NAME_PREFIX + "_" + getLongString(dataSourceObjId), super(NAME_PREFIX + "_" + getLongString(dataSourceObjId),
Bundle.RootFactory_DataSourceFilesNode_displayName(), Bundle.RootFactory_DataSourceFilesNode_displayName(),
@ -326,6 +504,9 @@ public class RootFactory {
} }
} }
/**
* Root node for displaying "View" for file types.
*/
@Messages({"RootFactory_ViewsRootNode_displayName=Views"}) @Messages({"RootFactory_ViewsRootNode_displayName=Views"})
public static class ViewsRootNode extends StaticTreeNode { public static class ViewsRootNode extends StaticTreeNode {
@ -339,7 +520,13 @@ public class RootFactory {
public static final String getNamePrefix() { public static final String getNamePrefix() {
return NAME_PREFIX; return NAME_PREFIX;
} }
/**
* Main constructor.
*
* @param dataSourceObjId The data source object id or null for no
* filter.
*/
public ViewsRootNode(Long dataSourceObjId) { public ViewsRootNode(Long dataSourceObjId) {
super(NAME_PREFIX + "_" + getLongString(dataSourceObjId), super(NAME_PREFIX + "_" + getLongString(dataSourceObjId),
Bundle.RootFactory_ViewsRootNode_displayName(), Bundle.RootFactory_ViewsRootNode_displayName(),
@ -348,6 +535,9 @@ public class RootFactory {
} }
} }
/**
* Root node for "Data Artifacts" in the tree.
*/
@Messages({"RootFactory_DataArtifactsRootNode_displayName=Data Artifacts"}) @Messages({"RootFactory_DataArtifactsRootNode_displayName=Data Artifacts"})
public static class DataArtifactsRootNode extends StaticTreeNode { public static class DataArtifactsRootNode extends StaticTreeNode {
@ -361,7 +551,13 @@ public class RootFactory {
public static final String getNamePrefix() { public static final String getNamePrefix() {
return NAME_PREFIX; return NAME_PREFIX;
} }
/**
* Main constructor.
*
* @param dataSourceObjId The data source object id or null for no
* filter.
*/
public DataArtifactsRootNode(Long dataSourceObjId) { public DataArtifactsRootNode(Long dataSourceObjId) {
super(NAME_PREFIX + "_" + getLongString(dataSourceObjId), super(NAME_PREFIX + "_" + getLongString(dataSourceObjId),
Bundle.RootFactory_DataArtifactsRootNode_displayName(), Bundle.RootFactory_DataArtifactsRootNode_displayName(),
@ -370,6 +566,9 @@ public class RootFactory {
} }
} }
/**
* Root node for "Analysis Results" in the tree.
*/
@Messages({"RootFactory_AnalysisResultsRootNode_displayName=Analysis Results"}) @Messages({"RootFactory_AnalysisResultsRootNode_displayName=Analysis Results"})
public static class AnalysisResultsRootNode extends StaticTreeNode { public static class AnalysisResultsRootNode extends StaticTreeNode {
@ -383,7 +582,13 @@ public class RootFactory {
public static final String getNamePrefix() { public static final String getNamePrefix() {
return NAME_PREFIX; return NAME_PREFIX;
} }
/**
* Main constructor.
*
* @param dataSourceObjId The data source object id or null for no
* filter.
*/
public AnalysisResultsRootNode(Long dataSourceObjId) { public AnalysisResultsRootNode(Long dataSourceObjId) {
super(NAME_PREFIX + "_" + getLongString(dataSourceObjId), super(NAME_PREFIX + "_" + getLongString(dataSourceObjId),
Bundle.RootFactory_AnalysisResultsRootNode_displayName(), Bundle.RootFactory_AnalysisResultsRootNode_displayName(),
@ -392,6 +597,10 @@ public class RootFactory {
} }
} }
/**
* Root node for OS accounts in the tree.
*/
@Messages({"RootFactory_OsAccountsRootNode_displayName=OS Accounts"}) @Messages({"RootFactory_OsAccountsRootNode_displayName=OS Accounts"})
public static class OsAccountsRootNode extends StaticTreeNode { public static class OsAccountsRootNode extends StaticTreeNode {
@ -405,9 +614,15 @@ public class RootFactory {
public static final String getNamePrefix() { public static final String getNamePrefix() {
return NAME_PREFIX; return NAME_PREFIX;
} }
private final Long dataSourceObjId; private final Long dataSourceObjId;
/**
* Main constructor.
*
* @param dataSourceObjId The data source object id or null for no
* filter.
*/
public OsAccountsRootNode(Long dataSourceObjId) { public OsAccountsRootNode(Long dataSourceObjId) {
super(NAME_PREFIX + "_" + getLongString(dataSourceObjId), super(NAME_PREFIX + "_" + getLongString(dataSourceObjId),
Bundle.RootFactory_OsAccountsRootNode_displayName(), Bundle.RootFactory_OsAccountsRootNode_displayName(),
@ -423,6 +638,10 @@ public class RootFactory {
} }
/**
* Root node for tags in the tree.
*/
@Messages({"RootFactory_TagsRootNode_displayName=Tags"}) @Messages({"RootFactory_TagsRootNode_displayName=Tags"})
public static class TagsRootNode extends StaticTreeNode { public static class TagsRootNode extends StaticTreeNode {
@ -436,7 +655,13 @@ public class RootFactory {
public static final String getNamePrefix() { public static final String getNamePrefix() {
return NAME_PREFIX; return NAME_PREFIX;
} }
/**
* Main constructor.
*
* @param dataSourceObjId The data source object id or null for no
* filter.
*/
public TagsRootNode(Long dataSourceObjId) { public TagsRootNode(Long dataSourceObjId) {
super(NAME_PREFIX + "_" + getLongString(dataSourceObjId), super(NAME_PREFIX + "_" + getLongString(dataSourceObjId),
Bundle.RootFactory_TagsRootNode_displayName(), Bundle.RootFactory_TagsRootNode_displayName(),
@ -445,6 +670,10 @@ public class RootFactory {
} }
} }
/**
* Root node for reports in the tree.
*/
@Messages({"RootFactory_ReportsRootNode_displayName=Reports"}) @Messages({"RootFactory_ReportsRootNode_displayName=Reports"})
public static class ReportsRootNode extends StaticTreeNode { public static class ReportsRootNode extends StaticTreeNode {
@ -458,7 +687,10 @@ public class RootFactory {
public static final String getNameIdentifier() { public static final String getNameIdentifier() {
return NAME_ID; return NAME_ID;
} }
/**
* Main constructor.
*/
public ReportsRootNode() { public ReportsRootNode() {
super(NAME_ID, super(NAME_ID,
Bundle.RootFactory_ReportsRootNode_displayName(), Bundle.RootFactory_ReportsRootNode_displayName(),

View File

@ -26,6 +26,8 @@ import org.sleuthkit.autopsy.mainui.nodes.actions.ActionsFactory.ActionGroup;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.Host;
import org.sleuthkit.datamodel.Person;
import org.sleuthkit.datamodel.Report; import org.sleuthkit.datamodel.Report;
/** /**
@ -270,4 +272,18 @@ public interface ActionContext {
default Optional<Report> getReport() { default Optional<Report> getReport() {
return Optional.empty(); return Optional.empty();
} }
/**
* @return The person relevant to the node if present.
*/
default Optional<Person> getPerson() {
return Optional.empty();
}
/**
* @return The host relevant to the node if present.
*/
default Optional<Host> getHost() {
return Optional.empty();
}
} }

View File

@ -46,11 +46,18 @@ import org.sleuthkit.autopsy.actions.OpenReportAction;
import org.sleuthkit.autopsy.actions.ReplaceContentTagAction; import org.sleuthkit.autopsy.actions.ReplaceContentTagAction;
import org.sleuthkit.autopsy.actions.ViewArtifactAction; import org.sleuthkit.autopsy.actions.ViewArtifactAction;
import org.sleuthkit.autopsy.actions.ViewOsAccountAction; import org.sleuthkit.autopsy.actions.ViewOsAccountAction;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.DeleteDataSourceAction; import org.sleuthkit.autopsy.casemodule.DeleteDataSourceAction;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactItem; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactItem;
import org.sleuthkit.autopsy.datamodel.DataModelActionsFactory; import org.sleuthkit.autopsy.datamodel.DataModelActionsFactory;
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.datamodel.persons.DeletePersonAction;
import org.sleuthkit.autopsy.datamodel.persons.EditPersonAction;
import org.sleuthkit.autopsy.datasourcesummary.ui.ViewSummaryInformationAction; import org.sleuthkit.autopsy.datasourcesummary.ui.ViewSummaryInformationAction;
import org.sleuthkit.autopsy.directorytree.CollapseAction; import org.sleuthkit.autopsy.directorytree.CollapseAction;
import org.sleuthkit.autopsy.directorytree.ExportCSVAction; import org.sleuthkit.autopsy.directorytree.ExportCSVAction;
@ -68,7 +75,9 @@ import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.DataArtifact; import org.sleuthkit.datamodel.DataArtifact;
import org.sleuthkit.datamodel.Host;
import org.sleuthkit.datamodel.OsAccount; import org.sleuthkit.datamodel.OsAccount;
import org.sleuthkit.datamodel.Person;
import org.sleuthkit.datamodel.Report; import org.sleuthkit.datamodel.Report;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
@ -180,6 +189,10 @@ public final class ActionsFactory {
.ifPresent(ag -> actionGroups.add(ag)); .ifPresent(ag -> actionGroups.add(ag));
getHostActions(actionContext).ifPresent(ag -> actionGroups.add(ag));
getPersonActions(actionContext).ifPresent(ag -> actionGroups.add(ag));
List<Action> actionList = new ArrayList<>(); List<Action> actionList = new ArrayList<>();
for (ActionGroup aGroup : actionGroups) { for (ActionGroup aGroup : actionGroups) {
if (aGroup != null) { if (aGroup != null) {
@ -555,6 +568,70 @@ public final class ActionsFactory {
return Bundle.ActionsFactory_getAssociatedTypeStr_associated(); return Bundle.ActionsFactory_getAssociatedTypeStr_associated();
} }
} }
/**
* Returns an action group of host actions if host is present in action
* context. Otherwise, returns empty.
*
* @param actionContext The action context.
*
* @return The action group or empty.
*/
private static Optional<ActionGroup> getHostActions(ActionContext actionContext) {
return actionContext.getHost()
.flatMap(host -> {
// if there is a host, then provide actions
if (host != null) {
List<Action> actionsList = new ArrayList<>();
// Add the appropriate Person action
Optional<Person> parent;
try {
parent = Case.getCurrentCaseThrows().getSleuthkitCase().getPersonManager().getPerson(host);
} catch (NoCurrentCaseException | TskCoreException ex) {
logger.log(Level.WARNING, String.format("Error fetching parent person of host: %s", host.getName() == null ? "<null>" : host.getName()), ex);
return Optional.empty();
}
// if there is a parent, only give option to remove parent person.
if (parent.isPresent()) {
actionsList.add(new RemoveParentPersonAction(host, parent.get()));
} else {
actionsList.add(new AssociatePersonsMenuAction(host));
}
// Add option to merge hosts
actionsList.add(new MergeHostMenuAction(host));
return Optional.of(new ActionGroup(actionsList));
} else {
return Optional.empty();
}
});
}
/**
* Returns an action group of person actions if person is present in action
* context. Otherwise, returns empty.
*
* @param actionContext The action context.
*
* @return The action group or empty.
*/
private static Optional<ActionGroup> getPersonActions(ActionContext actionContext) {
return actionContext.getPerson()
.flatMap(person -> {
if (person == null) {
return Optional.empty();
} else {
return Optional.of(new ActionGroup(Arrays.asList(
new EditPersonAction(person),
new DeletePersonAction(person)
)));
}
});
}
/** /**
* Represents a group of related actions. * Represents a group of related actions.