Autopsy 4.22.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
InterestingHits.java
Go to the documentation of this file.
1/*
2 * Autopsy Forensic Browser
3 *
4 * Copyright 2011-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 */
19package org.sleuthkit.autopsy.datamodel;
20
21import java.beans.PropertyChangeEvent;
22import java.beans.PropertyChangeListener;
23import java.sql.ResultSet;
24import java.sql.SQLException;
25import java.util.ArrayList;
26import java.util.Collections;
27import java.util.EnumSet;
28import java.util.HashMap;
29import java.util.HashSet;
30import java.util.LinkedHashMap;
31import java.util.List;
32import java.util.Map;
33import java.util.Observable;
34import java.util.Observer;
35import java.util.Set;
36import java.util.logging.Level;
37import org.openide.nodes.ChildFactory;
38import org.openide.nodes.Children;
39import org.openide.nodes.Node;
40import org.openide.nodes.Sheet;
41import org.openide.util.NbBundle;
42import org.openide.util.WeakListeners;
43import org.openide.util.lookup.Lookups;
44import org.sleuthkit.autopsy.casemodule.Case;
45import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
46import org.sleuthkit.autopsy.coreutils.Logger;
47import org.sleuthkit.autopsy.ingest.IngestManager;
48import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
49import org.sleuthkit.datamodel.BlackboardArtifact;
50import org.sleuthkit.datamodel.BlackboardAttribute;
51import org.sleuthkit.datamodel.SleuthkitCase;
52import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery;
53import org.sleuthkit.datamodel.TskCoreException;
54import org.sleuthkit.datamodel.AnalysisResult;
55import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode;
56
57public class InterestingHits implements AutopsyVisitableItem {
58
59 private static final Logger logger = Logger.getLogger(InterestingHits.class.getName());
62
63 private SleuthkitCase skCase;
65 private final long filteringDSObjId; // 0 if not filtering/grouping by data source
66 private final BlackboardArtifact.Type artifactType;
67
76 public InterestingHits(SleuthkitCase skCase, BlackboardArtifact.Type artifactType) {
77 this(skCase, artifactType, 0);
78 }
79
89 public InterestingHits(SleuthkitCase skCase, BlackboardArtifact.Type artifactType, long objId) {
90 this.skCase = skCase;
91 this.artifactType = artifactType;
92 this.filteringDSObjId = objId;
93 interestingResults.update();
94 }
95
99 private class InterestingResults extends Observable {
100
101 // NOTE: the map can be accessed by multiple worker threads and needs to be synchronized
102 private final Map<String, Set<Long>> interestingItemsMap = new LinkedHashMap<>();
103
111 List<String> getSetNames() {
112 List<String> setNames;
113 synchronized (interestingItemsMap) {
114 setNames = new ArrayList<>(interestingItemsMap.keySet());
115 }
116 Collections.sort(setNames, (a, b) -> a.compareToIgnoreCase(b));
117 return setNames;
118 }
119
129 Set<Long> getArtifactIds(String setName) {
130 synchronized (interestingItemsMap) {
131 return new HashSet<>(interestingItemsMap.getOrDefault(setName, Collections.emptySet()));
132 }
133 }
134
138 void update() {
139 synchronized (interestingItemsMap) {
140 interestingItemsMap.clear();
141 }
143 setChanged();
144 notifyObservers();
145 }
146
147 /*
148 * Reads the artifacts of specified type, grouped by Set, and loads into
149 * the interestingItemsMap
150 */
151 @SuppressWarnings("deprecation")
152 private void loadArtifacts() {
153 if (skCase == null) {
154 return;
155 }
156
157 int setNameId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID();
158
159 String query = "SELECT value_text, blackboard_artifacts.artifact_obj_id " //NON-NLS
160 + "FROM blackboard_attributes,blackboard_artifacts WHERE " //NON-NLS
161 + "attribute_type_id=" + setNameId //NON-NLS
162 + " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS
163 + " AND blackboard_artifacts.artifact_type_id = " + artifactType.getTypeID(); //NON-NLS
164 if (filteringDSObjId > 0) {
165 query += " AND blackboard_artifacts.data_source_obj_id = " + filteringDSObjId;
166 }
167
168 try (CaseDbQuery dbQuery = skCase.executeQuery(query)) {
169 synchronized (interestingItemsMap) {
170 ResultSet resultSet = dbQuery.getResultSet();
171 while (resultSet.next()) {
172 String value = resultSet.getString("value_text"); //NON-NLS
173 long artifactObjId = resultSet.getLong("artifact_obj_id"); //NON-NLS
174 interestingItemsMap
175 .computeIfAbsent(value, (k) -> new HashSet<>())
176 .add(artifactObjId);
177 }
178 }
179 } catch (TskCoreException | SQLException ex) {
180 logger.log(Level.WARNING, "SQL Exception occurred: ", ex); //NON-NLS
181 }
182 }
183 }
184
185 @Override
186 public <T> T accept(AutopsyItemVisitor<T> visitor) {
187 return visitor.visit(this);
188 }
189
193 private class SetNameFactory extends ChildFactory.Detachable<String> implements Observer {
194
195 /*
196 * This should probably be in the top-level class, but the factory has
197 * nice methods for its startup and shutdown, so it seemed like a
198 * cleaner place to register the property change listener.
199 */
200 private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
201 String eventType = evt.getPropertyName();
202 if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
209 try {
217 ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
218 if (null != eventData && (eventData.getBlackboardArtifactType().getTypeID() == artifactType.getTypeID())) {
219 interestingResults.update();
220 }
221 } catch (NoCurrentCaseException notUsed) {
225 }
226 } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
227 || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
234 try {
236 interestingResults.update();
237 } catch (NoCurrentCaseException notUsed) {
241 }
242 } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
243 // case was closed. Remove listeners so that we don't get called with a stale case handle
244 if (evt.getNewValue() == null) {
245 removeNotify();
246 skCase = null;
247 }
248 }
249 };
250
251 private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null);
252
253 @Override
254 protected boolean createKeys(List<String> list) {
255 list.addAll(interestingResults.getSetNames());
256 return true;
257 }
258
259 @Override
260 protected Node createNodeForKey(String key) {
261 return new SetNameNode(key);
262 }
263
264 @Override
265 public void update(Observable o, Object arg) {
266 refresh(true);
267 }
268
269 @Override
277
278 @Override
279 protected void finalize() throws Throwable {
280 super.finalize();
284 interestingResults.deleteObserver(this);
285 }
286 }
287
291 public class SetNameNode extends DisplayableItemNode implements Observer {
292
293 private final String setName;
294
295 public SetNameNode(String setName) {//, Set<Long> children) {
296 super(Children.create(new HitFactory(setName), true), Lookups.singleton(setName));
297 this.setName = setName;
298 super.setName(setName);
300 this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/interesting_item.png"); //NON-NLS
301 interestingResults.addObserver(this);
302 }
303
304 private void updateDisplayName() {
305 int sizeOfSet = interestingResults.getArtifactIds(setName).size();
306 super.setDisplayName(setName + " (" + sizeOfSet + ")");
307 }
308
309 @Override
310 public boolean isLeafTypeNode() {
311 return true;
312 }
313
314 @Override
315 protected Sheet createSheet() {
316 Sheet sheet = super.createSheet();
317 Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
318 if (sheetSet == null) {
319 sheetSet = Sheet.createPropertiesSet();
320 sheet.put(sheetSet);
321 }
322
323 sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.name"),
324 NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.name"),
325 NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.desc"),
326 getName()));
327
328 return sheet;
329 }
330
331 @Override
332 public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
333 return visitor.visit(this);
334 }
335
336 @Override
337 public void update(Observable o, Object arg) {
339 }
340
341 @Override
342 public String getItemType() {
347 return getClass().getName();
348 }
349 }
350
354 public class RootNode extends UpdatableCountTypeNode {
355
359 public RootNode() {
360 super(Children.create(new SetNameFactory(), true),
361 Lookups.singleton(artifactType),
362 artifactType.getDisplayName(),
365
371 setName(artifactType.getDisplayName());
372 this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/interesting_item.png"); //NON-NLS
373 }
374
375 @Override
376 public boolean isLeafTypeNode() {
377 return false;
378 }
379
380 @Override
381 protected Sheet createSheet() {
382 Sheet sheet = super.createSheet();
383 Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
384 if (sheetSet == null) {
385 sheetSet = Sheet.createPropertiesSet();
386 sheet.put(sheetSet);
387 }
388 sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.name"),
389 NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.name"),
390 NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.desc"),
391 getName()));
392 return sheet;
393 }
394
395 @Override
396 public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
397 return visitor.visit(this);
398 }
399
400 @Override
401 public String getItemType() {
406 return getClass().getName();
407 }
408 }
409
413 private class HitFactory extends BaseChildFactory<AnalysisResult> implements Observer {
414
415 private final String setName;
416 private final Map<Long, AnalysisResult> artifactHits = new HashMap<>();
417
423 private HitFactory(String setName) {
429 super(setName);
430 this.setName = setName;
431 interestingResults.addObserver(this);
432 }
433
434 @Override
435 protected List<AnalysisResult> makeKeys() {
436
437 if (skCase != null) {
438 interestingResults.getArtifactIds(setName).forEach((id) -> {
439 try {
440 if (!artifactHits.containsKey(id)) {
441 AnalysisResult art = skCase.getBlackboard().getAnalysisResultById(id);
442 //Cache attributes while we are off the EDT.
443 //See JIRA-5969
444 art.getAttributes();
445 artifactHits.put(id, art);
446 }
447 } catch (TskCoreException ex) {
448 logger.log(Level.SEVERE, "TSK Exception occurred", ex); //NON-NLS
449 }
450 });
451
452 return new ArrayList<>(artifactHits.values());
453 }
454 return Collections.emptyList();
455 }
456
457 @Override
458 protected Node createNodeForKey(AnalysisResult art) {
459 return new BlackboardArtifactNode(art);
460 }
461
462 @Override
463 public void update(Observable o, Object arg) {
464 refresh(true);
465 }
466
467 @Override
468 protected void onAdd() {
469 // No-op
470 }
471
472 @Override
473 protected void onRemove() {
474 // No-op
475 }
476 }
477}
static void removeEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition Case.java:757
static void addEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition Case.java:712
synchronized static Logger getLogger(String name)
Definition Logger.java:124
UpdatableCountTypeNode(Children children, Lookup lookup, String baseName, long filteringDSObjId, BlackboardArtifact.Type... types)
InterestingHits(SleuthkitCase skCase, BlackboardArtifact.Type artifactType)
static final Set< IngestManager.IngestModuleEvent > INGEST_MODULE_EVENTS_OF_INTEREST
static final Set< IngestManager.IngestJobEvent > INGEST_JOB_EVENTS_OF_INTEREST
InterestingHits(SleuthkitCase skCase, BlackboardArtifact.Type artifactType, long objId)
static synchronized IngestManager getInstance()
void removeIngestModuleEventListener(final PropertyChangeListener listener)
void removeIngestJobEventListener(final PropertyChangeListener listener)
void addIngestModuleEventListener(final PropertyChangeListener listener)
void addIngestJobEventListener(final PropertyChangeListener listener)

Copyright © 2012-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.