19package org.sleuthkit.autopsy.datamodel;
21import java.beans.PropertyChangeEvent;
22import java.beans.PropertyChangeListener;
23import java.sql.SQLException;
24import java.text.MessageFormat;
25import java.util.ArrayList;
26import java.util.Arrays;
27import java.util.Comparator;
28import java.util.EnumSet;
29import java.util.HashMap;
32import java.util.Map.Entry;
34import java.util.concurrent.atomic.AtomicLong;
35import java.util.concurrent.atomic.AtomicReference;
36import java.util.logging.Level;
37import java.util.stream.Collectors;
38import java.util.stream.IntStream;
39import org.apache.commons.lang3.StringUtils;
40import org.apache.commons.lang3.tuple.Pair;
41import org.openide.nodes.AbstractNode;
42import org.openide.nodes.ChildFactory;
43import org.openide.nodes.Children;
44import org.openide.nodes.Node;
45import org.openide.nodes.Sheet;
46import org.openide.util.NbBundle;
47import org.openide.util.NbBundle.Messages;
48import org.openide.util.WeakListeners;
49import org.openide.util.lookup.Lookups;
50import org.sleuthkit.autopsy.casemodule.Case;
51import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
52import org.sleuthkit.autopsy.coreutils.Logger;
53import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
54import static org.sleuthkit.autopsy.datamodel.AbstractContentNode.NO_DESCR;
55import org.sleuthkit.autopsy.guiutils.RefreshThrottler;
56import org.sleuthkit.autopsy.ingest.IngestManager;
57import org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent;
58import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
59import org.sleuthkit.datamodel.AbstractFile;
60import org.sleuthkit.datamodel.BlackboardArtifact;
61import org.sleuthkit.datamodel.BlackboardArtifact.Category;
62import org.sleuthkit.datamodel.BlackboardAttribute;
63import org.sleuthkit.datamodel.Content;
64import org.sleuthkit.datamodel.ContentVisitor;
65import org.sleuthkit.datamodel.DerivedFile;
66import org.sleuthkit.datamodel.Directory;
67import org.sleuthkit.datamodel.File;
68import org.sleuthkit.datamodel.FsContent;
69import org.sleuthkit.datamodel.LayoutFile;
70import org.sleuthkit.datamodel.LocalFile;
71import org.sleuthkit.datamodel.Score.Priority;
72import org.sleuthkit.datamodel.Score.Significance;
73import org.sleuthkit.datamodel.SlackFile;
74import org.sleuthkit.datamodel.SleuthkitCase;
75import org.sleuthkit.datamodel.TskCoreException;
76import org.sleuthkit.datamodel.VirtualDirectory;
86 @NbBundle.Messages({
"ScoreContent_badFilter_text=Bad Items",
87 "ScoreContent_susFilter_text=Suspicious Items"})
91 Bundle.ScoreContent_badFilter_text()),
93 Bundle.ScoreContent_susFilter_text());
115 return this.displayName;
120 return visitor.
visit(
this);
141 this.filteringDSObjId = dsObjId;
147 long filteringDataSourceObjId() {
148 return this.filteringDSObjId;
152 public <T> T accept(AutopsyItemVisitor<T> visitor) {
153 return visitor.visit(
this);
172 .map(evt -> evt.name())
173 .collect(Collectors.toSet());
186 private static PropertyChangeListener
getPcl(
final Runnable onRefresh,
final Runnable onRemove) {
187 return (PropertyChangeEvent evt) -> {
188 String eventType = evt.getPropertyName();
193 if (onRefresh !=
null) {
203 if (evt.getNewValue() ==
null && onRemove !=
null) {
210 if (onRefresh !=
null) {
235 String query =
" " + objIdAlias +
" IN (SELECT tsk_aggregate_score.obj_id FROM tsk_aggregate_score WHERE " + aggregateScoreFilter +
") ";
245 case SUS_ITEM_FILTER:
246 return " tsk_aggregate_score.significance = " + Significance.LIKELY_NOTABLE.getId()
247 +
" AND (tsk_aggregate_score.priority = " + Priority.NORMAL.getId() +
" OR tsk_aggregate_score.priority = " + Priority.OVERRIDE.getId() +
" )";
248 case BAD_ITEM_FILTER:
249 return " tsk_aggregate_score.significance = " + Significance.NOTABLE.getId()
250 +
" AND (tsk_aggregate_score.priority = " + Priority.NORMAL.getId() +
" OR tsk_aggregate_score.priority = " + Priority.OVERRIDE.getId() +
" )";
252 throw new IllegalArgumentException(MessageFormat.format(
"Unsupported filter type to get suspect content: {0}", filter));
265 return getFilter(filter,
"obj_id",
"data_source_obj_id", filteringDsObjId);
277 return getFilter(filter,
"artifacts.artifact_obj_id",
"artifacts.data_source_obj_id", filteringDsObjId);
288 String eventType = evt.getPropertyName();
294 if (
null != event && Category.ANALYSIS_RESULT.equals(event.getBlackboardArtifactType().getCategory())) {
311 @NbBundle.Messages(
"ScoreContent_ScoreContentNode_name=Score")
312 private static final String
NAME = Bundle.ScoreContent_ScoreContentNode_name();
314 ScoreContentsNode(SleuthkitCase
skCase,
long datasourceObjId) {
317 super.setDisplayName(
NAME);
318 this.setIconBaseWithExtension(
"org/sleuthkit/autopsy/images/red-circle-exclamation.png");
328 return visitor.
visit(
this);
333 "ScoreContent_createSheet_name_displayName=Name",
334 "ScoreContent_createSheet_name_desc=no description"})
336 Sheet sheet = super.createSheet();
337 Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
338 if (sheetSet ==
null) {
339 sheetSet = Sheet.createPropertiesSet();
344 Bundle.ScoreContent_createSheet_name_displayName(),
345 Bundle.ScoreContent_createSheet_name_desc(),
352 return getClass().getName();
370 private final PropertyChangeListener
weakPcl = WeakListeners.propertyChange(
pcl,
null);
376 this.datasourceObjId = dsObjId;
408 protected boolean createKeys(List<ScoreContent.ScoreContentFilter> list) {
409 list.addAll(Arrays.asList(
ScoreContent.ScoreContentFilter.values()));
410 typeNodeMap.values().forEach(nd -> nd.updateDisplayName());
431 super(Children.create(
new ScoreContentChildren(
filter,
skCase, dsObjId),
true), Lookups.singleton(
filter.getDisplayName()));
433 this.datasourceObjId = dsObjId;
438 super.setName(
filter.getName());
440 String tooltip =
filter.getDisplayName();
441 this.setShortDescription(tooltip);
442 switch (this.filter) {
443 case SUS_ITEM_FILTER:
444 this.setIconBaseWithExtension(
"org/sleuthkit/autopsy/images/yellow-circle-yield.png");
447 case BAD_ITEM_FILTER:
448 this.setIconBaseWithExtension(
"org/sleuthkit/autopsy/images/red-circle-exclamation.png");
455 void updateDisplayName() {
460 }
catch (TskCoreException ex) {
461 logger.log(Level.WARNING,
"An error occurred while fetching file counts", ex);
463 super.setDisplayName(
filter.getDisplayName() +
" (" + count +
")");
475 AtomicLong retVal =
new AtomicLong(0L);
476 AtomicReference<SQLException> exRef =
new AtomicReference(
null);
478 String query =
" COUNT(tsk_aggregate_score.obj_id) AS count FROM tsk_aggregate_score WHERE\n"
481 +
" AND tsk_aggregate_score.obj_id IN\n"
482 +
" (SELECT tsk_files.obj_id AS obj_id FROM tsk_files UNION\n"
483 +
" SELECT blackboard_artifacts.artifact_obj_id AS obj_id FROM blackboard_artifacts WHERE blackboard_artifacts.artifact_type_id IN\n"
484 +
" (SELECT artifact_type_id FROM blackboard_artifact_types WHERE category_type = " + Category.DATA_ARTIFACT.getID() +
")) ";
485 sleuthkitCase.getCaseDbAccessManager().select(query, (rs) -> {
488 retVal.set(rs.getLong(
"count"));
490 }
catch (SQLException ex) {
495 SQLException sqlEx = exRef.get();
497 throw new TskCoreException(
498 MessageFormat.format(
"A sql exception occurred fetching results with query: SELECT {0}", query),
507 return visitor.
visit(
this);
512 "ScoreContent_createSheet_filterType_displayName=Type",
513 "ScoreContent_createSheet_filterType_desc=no description"})
515 Sheet sheet = super.createSheet();
516 Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
517 if (sheetSet ==
null) {
518 sheetSet = Sheet.createPropertiesSet();
523 Bundle.ScoreContent_createSheet_filterType_displayName(),
524 Bundle.ScoreContent_createSheet_filterType_desc(),
525 filter.getDisplayName()));
548 private final PropertyChangeListener
pcl =
getPcl(
549 () -> ScoreContentChildren.this.refresh(
false),
550 () -> ScoreContentChildren.this.removeNotify());
552 private final PropertyChangeListener
weakPcl = WeakListeners.propertyChange(
pcl,
null);
554 private final SleuthkitCase
skCase;
561 super(
filter.getName(),
new ViewsKnownAndSlackFilter<>());
568 protected void onAdd() {
589 public boolean isRefreshRequired(PropertyChangeEvent evt) {
593 private List<Content> runFsQuery() {
594 List<Content> ret =
new ArrayList<>();
596 String fileFilter =
null;
597 String dataArtifactFilter =
null;
601 ret.addAll(
skCase.findAllFilesWhere(fileFilter));
602 ret.addAll(
skCase.getBlackboard().getDataArtifactsWhere(dataArtifactFilter));
603 }
catch (TskCoreException | IllegalArgumentException e) {
604 logger.log(Level.SEVERE, MessageFormat.format(
605 "Error getting files for the deleted content view using file filter: {0} data artifact filter: {1}",
606 StringUtils.defaultString(fileFilter,
"<null>"),
607 StringUtils.defaultString(dataArtifactFilter,
"<null>")), e);
615 protected List<Content>
makeKeys() {
620 protected Node createNodeForKey(Content key) {
621 return key.accept(
new ContentVisitor.Default<AbstractNode>() {
622 public FileNode visit(AbstractFile f) {
623 return new ScoreFileNode(f, false);
626 public FileNode visit(FsContent f) {
627 return new ScoreFileNode(f,
false);
631 public FileNode visit(LayoutFile f) {
632 return new ScoreFileNode(f,
false);
636 public FileNode visit(File f) {
637 return new ScoreFileNode(f,
false);
641 public FileNode visit(Directory f) {
642 return new ScoreFileNode(f,
false);
646 public FileNode visit(VirtualDirectory f) {
647 return new ScoreFileNode(f,
false);
651 public AbstractNode visit(SlackFile sf) {
652 return new ScoreFileNode(sf,
false);
656 public AbstractNode visit(LocalFile lf) {
657 return new ScoreFileNode(lf,
false);
661 public AbstractNode visit(DerivedFile df) {
662 return new ScoreFileNode(df,
false);
666 public AbstractNode visit(BlackboardArtifact ba) {
667 return new ScoreArtifactNode(ba);
671 protected AbstractNode defaultVisit(Content di) {
672 if (di instanceof AbstractFile) {
673 return visit((AbstractFile) di);
675 throw new UnsupportedOperationException(
"Not supported for this type of Displayable Item: " + di.toString());
689 Sheet sheet =
new Sheet();
690 Sheet.Set sheetSet = Sheet.createPropertiesSet();
693 List<NodeProperty<?>> properties =
new ArrayList<>();
698 StringUtils.defaultString(path)));
706 if (StringUtils.isNotBlank(path)) {
714 if (time !=
null && time > 0) {
722 properties.forEach((property) -> {
723 sheetSet.put(property);
733 private static final List<BlackboardAttribute.Type>
TIME_ATTRS = Arrays.asList(
734 BlackboardAttribute.Type.TSK_DATETIME,
735 BlackboardAttribute.Type.TSK_DATETIME_ACCESSED,
736 BlackboardAttribute.Type.TSK_DATETIME_RCVD,
737 BlackboardAttribute.Type.TSK_DATETIME_SENT,
738 BlackboardAttribute.Type.TSK_DATETIME_CREATED,
739 BlackboardAttribute.Type.TSK_DATETIME_MODIFIED,
740 BlackboardAttribute.Type.TSK_DATETIME_START,
741 BlackboardAttribute.Type.TSK_DATETIME_END,
742 BlackboardAttribute.Type.TSK_DATETIME_DELETED,
743 BlackboardAttribute.Type.TSK_DATETIME_PASSWORD_RESET,
744 BlackboardAttribute.Type.TSK_DATETIME_PASSWORD_FAIL
748 .mapToObj(idx -> Pair.of(
TIME_ATTRS.get(idx).getTypeID(), idx))
749 .collect(Collectors.toMap(Entry::getKey, Entry::getValue, (v1, v2) -> v1));
757 BlackboardAttribute timeAttr =
artifact.getAttributes().stream()
759 .sorted(Comparator.comparing(attr ->
TIME_ATTR_IMPORTANCE.get(attr.getAttributeType().getTypeID())))
763 if (timeAttr !=
null) {
764 return timeAttr.getValueLong();
766 return (
artifact.getParent() instanceof AbstractFile) ? ((AbstractFile)
artifact.getParent()).getCtime() :
null;
768 }
catch (TskCoreException ex) {
769 logger.log(Level.WARNING,
"An exception occurred while fetching time for artifact", ex);
778 this.
content.getType().getDisplayName(),
779 this.content.getUniquePath(),
782 }
catch (TskCoreException ex) {
783 logger.log(Level.WARNING,
"An error occurred while fetching sheet data for score artifact.", ex);
789 @Messages(
"ScoreContent_ScoreFileNode_type=File")
802 Bundle.ScoreContent_ScoreFileNode_type(),
803 this.content.getUniquePath(),
804 this.content.getCtime()
806 }
catch (TskCoreException ex) {
807 logger.log(Level.WARNING,
"An error occurred while fetching sheet data for score file.", ex);
static void removeEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
static Case getCurrentCaseThrows()
static void addEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
synchronized static Logger getLogger(String name)
static String getFormattedTime(long epochTime)
boolean directoryBrowseMode
static final Logger logger
abstract List< T > makeKeys()
BlackboardArtifactNode(BlackboardArtifact artifact, String iconPath)
final BlackboardArtifact artifact
DisplayableItemNode(Children children)
FileNode(AbstractFile file)
Long getTime(BlackboardArtifact artifact)
static final List< BlackboardAttribute.Type > TIME_ATTRS
static final Map< Integer, Integer > TIME_ATTR_IMPORTANCE
static final Logger logger
synchronized Sheet createSheet()
ScoreArtifactNode(BlackboardArtifact artifact)
static long calculateItems(SleuthkitCase sleuthkitCase, ScoreContent.ScoreContentFilter filter, long datasourceObjId)
static final Logger logger
final long datasourceObjId
final ScoreContent.ScoreContentFilter filter
final Map< ScoreContentFilter, ScoreContentsChildren.ScoreContentNode > typeNodeMap
final RefreshThrottler refreshThrottler
boolean createKeys(List< ScoreContent.ScoreContentFilter > list)
Node createNodeForKey(ScoreContent.ScoreContentFilter key)
final PropertyChangeListener weakPcl
boolean isRefreshRequired(PropertyChangeEvent evt)
final long datasourceObjId
final PropertyChangeListener pcl
ScoreContentsChildren(SleuthkitCase skCase, long dsObjId)
synchronized Sheet createSheet()
static final Logger logger
ScoreFileNode(AbstractFile af, boolean directoryBrowseMode)
static boolean isRefreshRequired(PropertyChangeEvent evt)
static final String DATE_PROP
static String getFilter(ScoreContent.ScoreContentFilter filter, String objIdAlias, String dsIdAlias, long filteringDSObjId)
static final String SOURCE_PROP
static String getFileFilter(ScoreContent.ScoreContentFilter filter, long filteringDsObjId)
static final Set< IngestManager.IngestJobEvent > INGEST_JOB_EVENTS_OF_INTEREST
static String getDataArtifactFilter(ScoreContent.ScoreContentFilter filter, long filteringDsObjId)
ScoreContent(SleuthkitCase skCase)
static final Set< String > CASE_EVENTS_OF_INTEREST_STRS
final long filteringDSObjId
ScoreContent(SleuthkitCase skCase, long dsObjId)
static PropertyChangeListener getPcl(final Runnable onRefresh, final Runnable onRemove)
static final String PATH_PROP
static final String TYPE_PROP
SleuthkitCase getSleuthkitCase()
static final Set< IngestManager.IngestModuleEvent > INGEST_MODULE_EVENTS_OF_INTEREST
static Sheet createScoreSheet(String type, String path, Long time)
static String getScoreFilter(ScoreContentFilter filter)
static final Set< Case.Events > CASE_EVENTS_OF_INTEREST
void registerForIngestModuleEvents()
void unregisterEventListener()
static synchronized IngestManager getInstance()
void removeIngestModuleEventListener(final PropertyChangeListener listener)
void removeIngestJobEventListener(final PropertyChangeListener listener)
void addIngestModuleEventListener(final PropertyChangeListener listener)
void addIngestJobEventListener(final PropertyChangeListener listener)
BLACKBOARD_ARTIFACT_TAG_DELETED
BLACKBOARD_ARTIFACT_TAG_ADDED
ScoreContentFilter(int id, String name, String displayName)
public< T > T accept(AutopsyItemVisitor< T > visitor)
T visit(DataSourceFilesNode in)