Autopsy  4.20.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
HostNode.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2021 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.datamodel;
20 
21 import java.beans.PropertyChangeEvent;
22 import java.beans.PropertyChangeListener;
23 import java.util.ArrayList;
24 import java.util.EnumSet;
25 import java.util.List;
26 import java.util.Optional;
27 import java.util.function.Function;
28 import java.util.logging.Level;
29 import java.util.stream.Collectors;
30 import javax.swing.Action;
31 import org.openide.nodes.ChildFactory;
32 
33 import org.openide.nodes.Children;
34 import org.openide.nodes.Node;
35 import org.openide.nodes.Sheet;
36 import org.openide.util.NbBundle;
37 import org.openide.util.NbBundle.Messages;
38 import org.openide.util.WeakListeners;
39 import org.openide.util.lookup.Lookups;
47 import org.sleuthkit.datamodel.DataSource;
48 import org.sleuthkit.datamodel.Host;
49 import org.sleuthkit.datamodel.Person;
50 import org.sleuthkit.datamodel.SleuthkitVisitableItem;
51 import org.sleuthkit.datamodel.TskCoreException;
52 
57 @NbBundle.Messages(value = {"HostGroupingNode_unknownHostNode_title=Unknown Host"})
58 public class HostNode extends DisplayableItemNode {
59 
63  private static class HostGroupingChildren extends ChildFactory.Detachable<DataSourceGrouping> {
64 
65  private static final Logger logger = Logger.getLogger(HostGroupingChildren.class.getName());
66 
67  private final Host host;
68  private final Function<DataSourceGrouping, Node> dataSourceToNode;
69 
76  HostGroupingChildren(Function<DataSourceGrouping, Node> dataSourceToNode, Host host) {
77  this.host = host;
78  this.dataSourceToNode = dataSourceToNode;
79  }
80 
86  private final PropertyChangeListener dataSourceAddedPcl = new PropertyChangeListener() {
87  @Override
88  public void propertyChange(PropertyChangeEvent evt) {
89  String eventType = evt.getPropertyName();
90  if (eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())
91  || eventType.equals(Case.Events.HOSTS_DELETED.toString())) {
92  refresh(true);
93  }
94  }
95  };
96 
97  private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(dataSourceAddedPcl, null);
98 
99  @Override
100  protected void addNotify() {
101  super.addNotify();
103  }
104 
105  @Override
106  protected void finalize() throws Throwable {
107  super.finalize();
109  }
110 
111  @Override
112  protected Node createNodeForKey(DataSourceGrouping key) {
113  return this.dataSourceToNode.apply(key);
114  }
115 
116  @Override
117  protected boolean createKeys(List<DataSourceGrouping> toPopulate) {
118  List<DataSource> dataSources = null;
119  try {
120  dataSources = Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getDataSourcesForHost(host);
121  } catch (NoCurrentCaseException | TskCoreException ex) {
122  String hostName = host == null || host.getName() == null ? "<unknown>" : host.getName();
123  logger.log(Level.WARNING, String.format("Unable to get data sources for host: %s", hostName), ex);
124  }
125 
126  if (dataSources != null) {
127  toPopulate.addAll(dataSources.stream()
128  .filter(ds -> ds != null)
129  .map(DataSourceGrouping::new)
130  .sorted((a, b) -> getNameOrEmpty(a).compareToIgnoreCase(getNameOrEmpty(b)))
131  .collect(Collectors.toList()));
132  }
133 
134  return true;
135  }
136 
144  private String getNameOrEmpty(DataSourceGrouping dsGroup) {
145  return (dsGroup == null || dsGroup.getDataSource() == null || dsGroup.getDataSource().getName() == null)
146  ? ""
147  : dsGroup.getDataSource().getName();
148  }
149  }
150 
151  private static final Logger logger = Logger.getLogger(HostNode.class.getName());
152  private static final String ICON_PATH = "org/sleuthkit/autopsy/images/host.png";
153  private static final CreateSleuthkitNodeVisitor CREATE_TSK_NODE_VISITOR = new CreateSleuthkitNodeVisitor();
154 
159  private static final Function<DataSourceGrouping, Node> HOST_DATA_SOURCES = key -> {
160  if (key.getDataSource() instanceof SleuthkitVisitableItem) {
161  return ((SleuthkitVisitableItem) key.getDataSource()).accept(CREATE_TSK_NODE_VISITOR);
162  } else {
163  return null;
164  }
165  };
166 
170  private static final Function<DataSourceGrouping, Node> HOST_GROUPING_CONVERTER = key -> {
171  if (key == null || key.getDataSource() == null) {
172  return null;
173  }
174 
175  return new DataSourceGroupingNode(key.getDataSource());
176  };
177 
181  private final PropertyChangeListener hostChangePcl = new PropertyChangeListener() {
182  @Override
183  public void propertyChange(PropertyChangeEvent evt) {
184  String eventType = evt.getPropertyName();
185  if (hostId != null && eventType.equals(Case.Events.HOSTS_UPDATED.toString()) && evt instanceof HostsUpdatedEvent) {
186  ((HostsUpdatedEvent) evt).getHosts().stream()
187  .filter(h -> h != null && h.getHostId() == hostId)
188  .findFirst()
189  .ifPresent((newHost) -> {
190  setName(newHost.getName());
191  setDisplayName(newHost.getName());
192  });
193  }
194  }
195  };
196 
197  private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(hostChangePcl, null);
198 
199  /*
200  * Get the host name or 'unknown host' if null.
201  *
202  * @param host The host.
203  * @return The display name.
204  */
205  private static String getHostName(Host host) {
206  return (host == null || host.getName() == null)
207  ? Bundle.HostGroupingNode_unknownHostNode_title()
208  : host.getName();
209  }
210 
211  private final Host host;
212  private final Long hostId;
213 
220  HostNode(HostDataSources hosts) {
221  this(Children.create(new HostGroupingChildren(HOST_DATA_SOURCES, hosts.getHost()), true), hosts.getHost());
222  }
223 
230  HostNode(HostGrouping hostGrouping) {
231  this(Children.create(new HostGroupingChildren(HOST_GROUPING_CONVERTER, hostGrouping.getHost()), true), hostGrouping.getHost());
232  }
233 
240  private HostNode(Children children, Host host) {
241  this(children, host, getHostName(host));
242  }
243 
251  private HostNode(Children children, Host host, String displayName) {
252  super(children,
253  host == null ? Lookups.fixed(displayName) : Lookups.fixed(host, displayName));
254 
255  hostId = host == null ? null : host.getHostId();
256  Case.addEventTypeSubscriber(EnumSet.of(Case.Events.HOSTS_UPDATED), weakPcl);
257  super.setName(displayName);
258  super.setDisplayName(displayName);
259  this.setIconBaseWithExtension(ICON_PATH);
260  this.host = host;
261  }
262 
263  @Override
264  public boolean isLeafTypeNode() {
265  return false;
266  }
267 
268  @Override
269  public String getItemType() {
270  return getClass().getName();
271  }
272 
273  @Override
274  public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
275  return visitor.visit(this);
276  }
277 
278  @Messages({
279  "HostNode_createSheet_nameProperty=Name",})
280  @Override
281  protected Sheet createSheet() {
282  Sheet sheet = Sheet.createDefault();
283  Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
284  if (sheetSet == null) {
285  sheetSet = Sheet.createPropertiesSet();
286  sheet.put(sheetSet);
287  }
288 
289  sheetSet.put(new NodeProperty<>("Name", Bundle.HostNode_createSheet_nameProperty(), "", getDisplayName())); //NON-NLS
290 
291  return sheet;
292  }
293 
294  @Override
295  @Messages({"HostNode_actions_associateWithExisting=Associate with existing person...",
296  "HostNode_actions_associateWithNew=Associate with new person...",
297  "# {0} - hostName",
298  "HostNode_actions_removeFromPerson=Remove from person ({0})"})
299  public Action[] getActions(boolean context) {
300 
301  List<Action> actionsList = new ArrayList<>();
302 
303  // if there is a host, then provide actions
304  if (this.host != null) {
305 
306  // Add the appropriate Person action
307  Optional<Person> parent;
308  try {
309  parent = Case.getCurrentCaseThrows().getSleuthkitCase().getPersonManager().getPerson(this.host);
310  } catch (NoCurrentCaseException | TskCoreException ex) {
311  logger.log(Level.WARNING, String.format("Error fetching parent person of host: %s", this.host.getName() == null ? "<null>" : this.host.getName()), ex);
312  return new Action[0];
313  }
314 
315  // if there is a parent, only give option to remove parent person.
316  if (parent.isPresent()) {
317  actionsList.add(new RemoveParentPersonAction(this.host, parent.get()));
318  } else {
319  actionsList.add(new AssociatePersonsMenuAction(this.host));
320  }
321 
322  // Add option to merge hosts
323  actionsList.add(new MergeHostMenuAction(this.host));
324  }
325  return actionsList.toArray(new Action[actionsList.size()]);
326  }
327 }
static String getHostName(Host host)
Definition: HostNode.java:205
boolean createKeys(List< DataSourceGrouping > toPopulate)
Definition: HostNode.java:117
Action[] getActions(boolean context)
Definition: HostNode.java:299
HostNode(Children children, Host host)
Definition: HostNode.java:240
HostNode(Children children, Host host, String displayName)
Definition: HostNode.java:251
final Function< DataSourceGrouping, Node > dataSourceToNode
Definition: HostNode.java:68
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static void addEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition: Case.java:704
static void removeEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition: Case.java:749

Copyright © 2012-2022 Basis Technology. Generated on: Tue Aug 1 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.