19 package org.sleuthkit.autopsy.datamodel;
21 import java.beans.PropertyChangeEvent;
22 import java.beans.PropertyChangeListener;
23 import java.sql.SQLException;
24 import java.text.MessageFormat;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.Comparator;
28 import java.util.EnumSet;
29 import java.util.HashMap;
30 import java.util.List;
32 import java.util.Map.Entry;
34 import java.util.concurrent.atomic.AtomicLong;
35 import java.util.concurrent.atomic.AtomicReference;
36 import java.util.logging.Level;
37 import java.util.stream.Collectors;
38 import java.util.stream.IntStream;
39 import org.apache.commons.lang3.StringUtils;
40 import org.apache.commons.lang3.tuple.Pair;
41 import org.openide.nodes.AbstractNode;
42 import org.openide.nodes.ChildFactory;
43 import org.openide.nodes.Children;
44 import org.openide.nodes.Node;
45 import org.openide.nodes.Sheet;
46 import org.openide.util.NbBundle;
47 import org.openide.util.NbBundle.Messages;
48 import org.openide.util.WeakListeners;
49 import org.openide.util.lookup.Lookups;
61 import org.
sleuthkit.datamodel.BlackboardArtifact.Category;
86 @NbBundle.Messages({
"ScoreContent_badFilter_text=Bad Items",
87 "ScoreContent_susFilter_text=Suspicious Items"})
90 BAD_ITEM_FILTER(0,
"BAD_ITEM_FILTER",
91 Bundle.ScoreContent_badFilter_text()),
92 SUS_ITEM_FILTER(1,
"SUS_ITEM_FILTER",
93 Bundle.ScoreContent_susFilter_text());
102 this.displayName = displayName;
115 return this.displayName;
120 return visitor.
visit(
this);
141 this.filteringDSObjId = dsObjId;
147 long filteringDataSourceObjId() {
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) {
206 }
else if (CASE_EVENTS_OF_INTEREST_STRS.contains(eventType)) {
210 if (onRefresh != null) {
235 String query =
" " + objIdAlias +
" IN (SELECT tsk_aggregate_score.obj_id FROM tsk_aggregate_score WHERE " + aggregateScoreFilter +
") ";
237 if (filteringDSObjId > 0) {
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();
315 super(Children.create(
new ScoreContentsChildren(skCase, datasourceObjId),
true), Lookups.singleton(NAME));
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) {
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);
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"
480 + ((datasourceObjId > 0) ?
"AND tsk_aggregate_score.data_source_obj_id = \n" + datasourceObjId :
"")
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<>());
563 this.filter = filter;
568 protected void onAdd() {
576 protected void onRemove() {
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() {
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());
683 private static final String SOURCE_PROP =
"Source";
684 private static final String TYPE_PROP =
"Type";
685 private static final String PATH_PROP =
"Path";
686 private static final String DATE_PROP =
"Created Date";
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
747 private static final Map<Integer, Integer> TIME_ATTR_IMPORTANCE = IntStream.range(0, TIME_ATTRS.size())
748 .mapToObj(idx -> Pair.of(TIME_ATTRS.get(idx).getTypeID(), idx))
749 .collect(Collectors.toMap(Entry::getKey, Entry::getValue, (v1, v2) -> v1));
755 private Long
getTime(BlackboardArtifact artifact) {
757 BlackboardAttribute timeAttr = artifact.getAttributes().stream()
758 .filter((attr) -> TIME_ATTR_IMPORTANCE.keySet().contains(attr.getAttributeType().getTypeID()))
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);
777 return createScoreSheet(
778 this.content.getType().getDisplayName(),
779 this.content.getUniquePath(),
780 getTime(this.content)
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")
795 super(af, directoryBrowseMode);
801 return createScoreSheet(
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);
void registerForIngestModuleEvents()
boolean createKeys(List< ScoreContent.ScoreContentFilter > list)
final PropertyChangeListener pcl
void removeIngestModuleEventListener(final PropertyChangeListener listener)
static boolean isRefreshRequired(PropertyChangeEvent evt)
SleuthkitCase getSleuthkitCase()
static synchronized IngestManager getInstance()
public< T > T accept(AutopsyItemVisitor< T > visitor)
static String getFileFilter(ScoreContent.ScoreContentFilter filter, long filteringDsObjId)
static final Set< String > CASE_EVENTS_OF_INTEREST_STRS
synchronized Sheet createSheet()
static final Set< IngestManager.IngestModuleEvent > INGEST_MODULE_EVENTS_OF_INTEREST
static Sheet createScoreSheet(String type, String path, Long time)
ScoreContent(SleuthkitCase skCase, long dsObjId)
ScoreContent(SleuthkitCase skCase)
final long filteringDSObjId
Long getTime(BlackboardArtifact artifact)
static String getFormattedTime(long epochTime)
final Map< ScoreContentFilter, ScoreContentsChildren.ScoreContentNode > typeNodeMap
void unregisterEventListener()
ScoreArtifactNode(BlackboardArtifact artifact)
static String getFilter(ScoreContent.ScoreContentFilter filter, String objIdAlias, String dsIdAlias, long filteringDSObjId)
void removeIngestJobEventListener(final PropertyChangeListener listener)
Node createNodeForKey(ScoreContent.ScoreContentFilter key)
static long calculateItems(SleuthkitCase sleuthkitCase, ScoreContent.ScoreContentFilter filter, long datasourceObjId)
void addIngestJobEventListener(final PropertyChangeListener listener)
ScoreContentsChildren(SleuthkitCase skCase, long dsObjId)
final long datasourceObjId
final ScoreContent.ScoreContentFilter filter
static final Logger logger
static String getDataArtifactFilter(ScoreContent.ScoreContentFilter filter, long filteringDsObjId)
T visit(DataSourceFilesNode in)
BLACKBOARD_ARTIFACT_TAG_ADDED
ScoreContentFilter(int id, String name, String displayName)
void addIngestModuleEventListener(final PropertyChangeListener listener)
static final Set< Case.Events > CASE_EVENTS_OF_INTEREST
boolean isRefreshRequired(PropertyChangeEvent evt)
synchronized static Logger getLogger(String name)
static final Set< IngestManager.IngestJobEvent > INGEST_JOB_EVENTS_OF_INTEREST
static Case getCurrentCaseThrows()
final long datasourceObjId
static void addEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
ScoreFileNode(AbstractFile af, boolean directoryBrowseMode)
final RefreshThrottler refreshThrottler
static String getScoreFilter(ScoreContentFilter filter)
static void removeEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
synchronized Sheet createSheet()
final PropertyChangeListener weakPcl
BLACKBOARD_ARTIFACT_TAG_DELETED
static final String NO_DESCR
static PropertyChangeListener getPcl(final Runnable onRefresh, final Runnable onRemove)