Autopsy 4.22.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
HashsetHits.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 static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_HASHSET_HIT;
51import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
52import org.sleuthkit.datamodel.SleuthkitCase;
53import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery;
54import org.sleuthkit.datamodel.TskCoreException;
55import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode;
56import org.sleuthkit.datamodel.AnalysisResult;
57
61public class HashsetHits implements AutopsyVisitableItem {
62
63 private static final String HASHSET_HITS = BlackboardArtifact.Type.TSK_HASHSET_HIT.getTypeName();
64 private static final String DISPLAY_NAME = BlackboardArtifact.Type.TSK_HASHSET_HIT.getDisplayName();
65 private static final Logger logger = Logger.getLogger(HashsetHits.class.getName());
68 private SleuthkitCase skCase;
70 private final long filteringDSObjId; // 0 if not filtering/grouping by data source
71
78 public HashsetHits(SleuthkitCase skCase) {
79 this(skCase, 0);
80 }
81
89 public HashsetHits(SleuthkitCase skCase, long objId) {
90 this.skCase = skCase;
91 this.filteringDSObjId = objId;
93 }
94
95 @Override
96 public <T> T accept(AutopsyItemVisitor<T> visitor) {
97 return visitor.visit(this);
98 }
99
104 private class HashsetResults extends Observable {
105
106 // maps hashset name to list of artifacts for that set
107 // NOTE: the map can be accessed by multiple worker threads and needs to be synchronized
108 private final Map<String, Set<Long>> hashSetHitsMap = new LinkedHashMap<>();
109
110 HashsetResults() {
111 update();
112 }
113
114 List<String> getSetNames() {
115 List<String> names;
116 synchronized (hashSetHitsMap) {
117 names = new ArrayList<>(hashSetHitsMap.keySet());
118 }
119 Collections.sort(names);
120 return names;
121 }
122
123 Set<Long> getArtifactIds(String hashSetName) {
124 synchronized (hashSetHitsMap) {
125 return hashSetHitsMap.get(hashSetName);
126 }
127 }
128
129 @SuppressWarnings("deprecation")
130 final void update() {
131 synchronized (hashSetHitsMap) {
132 hashSetHitsMap.clear();
133 }
134
135 if (skCase == null) {
136 return;
137 }
138
139 int setNameId = ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID();
140 int artId = TSK_HASHSET_HIT.getTypeID();
141 String query = "SELECT value_text,blackboard_artifacts.artifact_obj_id,attribute_type_id " //NON-NLS
142 + "FROM blackboard_attributes,blackboard_artifacts WHERE " //NON-NLS
143 + "attribute_type_id=" + setNameId //NON-NLS
144 + " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS
145 + " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS
146 if (filteringDSObjId > 0) {
147 query += " AND blackboard_artifacts.data_source_obj_id = " + filteringDSObjId;
148 }
149
150 try (CaseDbQuery dbQuery = skCase.executeQuery(query)) {
151 ResultSet resultSet = dbQuery.getResultSet();
152 synchronized (hashSetHitsMap) {
153 while (resultSet.next()) {
154 String setName = resultSet.getString("value_text"); //NON-NLS
155 long artifactObjId = resultSet.getLong("artifact_obj_id"); //NON-NLS
156 if (!hashSetHitsMap.containsKey(setName)) {
157 hashSetHitsMap.put(setName, new HashSet<>());
158 }
159 hashSetHitsMap.get(setName).add(artifactObjId);
160 }
161 }
162 } catch (TskCoreException | SQLException ex) {
163 logger.log(Level.WARNING, "SQL Exception occurred: ", ex); //NON-NLS
164 }
165
166 setChanged();
167 notifyObservers();
168 }
169 }
170
174 public class RootNode extends UpdatableCountTypeNode {
175
176 public RootNode() {
177 super(Children.create(new HashsetNameFactory(), true),
178 Lookups.singleton(DISPLAY_NAME),
181 TSK_HASHSET_HIT);
182
183 super.setName(HASHSET_HITS);
184 this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hashset_hits.png"); //NON-NLS
185 }
186
187 @Override
188 public boolean isLeafTypeNode() {
189 return false;
190 }
191
192 @Override
193 public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
194 return visitor.visit(this);
195 }
196
197 @Override
198 protected Sheet createSheet() {
199 Sheet sheet = super.createSheet();
200 Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
201 if (sheetSet == null) {
202 sheetSet = Sheet.createPropertiesSet();
203 sheet.put(sheetSet);
204 }
205
206 sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "HashsetHits.createSheet.name.name"),
207 NbBundle.getMessage(this.getClass(), "HashsetHits.createSheet.name.displayName"),
208 NbBundle.getMessage(this.getClass(), "HashsetHits.createSheet.name.desc"),
209 getName()));
210
211 return sheet;
212 }
213
214 @Override
215 public String getItemType() {
216 return getClass().getName();
217 }
218 }
219
223 private class HashsetNameFactory extends ChildFactory.Detachable<String> implements Observer {
224
225 /*
226 * This should probably be in the HashsetHits class, but the factory has
227 * nice methods for its startup and shutdown, so it seemed like a
228 * cleaner place to register the property change listener.
229 */
230 private final PropertyChangeListener pcl = new PropertyChangeListener() {
231 @Override
232 public void propertyChange(PropertyChangeEvent evt) {
233 String eventType = evt.getPropertyName();
234 if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
241 try {
248 ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
249 if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == TSK_HASHSET_HIT.getTypeID()) {
250 hashsetResults.update();
251 }
252 } catch (NoCurrentCaseException notUsed) {
256 }
257 } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
258 || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
265 try {
267 hashsetResults.update();
268 } catch (NoCurrentCaseException notUsed) {
272 }
273 } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
274 // case was closed. Remove listeners so that we don't get called with a stale case handle
275 if (evt.getNewValue() == null) {
276 removeNotify();
277 skCase = null;
278 }
279 }
280 }
281 };
282
283 private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null);
284
285 @Override
293
294 @Override
295 protected void finalize() throws Throwable {
296 super.finalize();
300 hashsetResults.deleteObserver(this);
301 }
302
303 @Override
304 protected boolean createKeys(List<String> list) {
305 list.addAll(hashsetResults.getSetNames());
306 return true;
307 }
308
309 @Override
310 protected Node createNodeForKey(String key) {
311 return new HashsetNameNode(key);
312 }
313
314 @Override
315 public void update(Observable o, Object arg) {
316 refresh(true);
317 }
318 }
319
323 public class HashsetNameNode extends DisplayableItemNode implements Observer {
324
325 private final String hashSetName;
326
328 super(Children.create(new HitFactory(hashSetName), true), Lookups.singleton(hashSetName));
329 super.setName(hashSetName);
330 this.hashSetName = hashSetName;
332 this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hashset_hits.png"); //NON-NLS
333 hashsetResults.addObserver(this);
334 }
335
339 private void updateDisplayName() {
340 super.setDisplayName(hashSetName + " (" + hashsetResults.getArtifactIds(hashSetName).size() + ")");
341 }
342
343 @Override
344 public boolean isLeafTypeNode() {
345 return true;
346 }
347
348 @Override
349 protected Sheet createSheet() {
350 Sheet sheet = super.createSheet();
351 Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
352 if (sheetSet == null) {
353 sheetSet = Sheet.createPropertiesSet();
354 sheet.put(sheetSet);
355 }
356
357 sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "HashsetHits.createSheet.name.name"),
358 NbBundle.getMessage(this.getClass(), "HashsetHits.createSheet.name.displayName"),
359 NbBundle.getMessage(this.getClass(), "HashsetHits.createSheet.name.desc"),
360 getName()));
361
362 return sheet;
363 }
364
365 @Override
366 public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
367 return visitor.visit(this);
368 }
369
370 @Override
371 public void update(Observable o, Object arg) {
373 }
374
375 @Override
376 public String getItemType() {
381 return getClass().getName();
382 }
383 }
384
388 private class HitFactory extends BaseChildFactory<AnalysisResult> implements Observer {
389
390 private final String hashsetName;
391 private final Map<Long, AnalysisResult> artifactHits = new HashMap<>();
392
393 private HitFactory(String hashsetName) {
394 super(hashsetName);
395 this.hashsetName = hashsetName;
396 }
397
398 @Override
399 protected void onAdd() {
400 hashsetResults.addObserver(this);
401 }
402
403 @Override
404 protected void onRemove() {
405 hashsetResults.deleteObserver(this);
406 }
407
408 @Override
409 protected Node createNodeForKey(AnalysisResult key) {
410 return new BlackboardArtifactNode(key);
411 }
412
413 @Override
414 public void update(Observable o, Object arg) {
415 refresh(true);
416 }
417
418 @Override
419 protected List<AnalysisResult> makeKeys() {
420 if (skCase != null) {
421
422 hashsetResults.getArtifactIds(hashsetName).forEach((id) -> {
423 try {
424 if (!artifactHits.containsKey(id)) {
425 AnalysisResult art = skCase.getBlackboard().getAnalysisResultById(id);
426 //Cache attributes while we are off the EDT.
427 //See JIRA-5969
428 art.getAttributes();
429 artifactHits.put(id, art);
430 }
431 } catch (TskCoreException ex) {
432 logger.log(Level.SEVERE, "TSK Exception occurred", ex); //NON-NLS
433 }
434 });
435 return new ArrayList<>(artifactHits.values());
436 }
437 return Collections.emptyList();
438 }
439 }
440}
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)
static final Set< IngestManager.IngestJobEvent > INGEST_JOB_EVENTS_OF_INTEREST
static final Set< IngestManager.IngestModuleEvent > INGEST_MODULE_EVENTS_OF_INTEREST
HashsetHits(SleuthkitCase skCase, 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.