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;
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:
248 case BAD_ITEM_FILTER:
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();
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() {
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();
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);
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;
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);
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));
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) {
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)
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()
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()
Blackboard getBlackboard()
static final Type TSK_DATETIME_END
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
static final Type TSK_DATETIME_MODIFIED
Long getTime(BlackboardArtifact artifact)
static String getFormattedTime(long epochTime)
final Map< ScoreContentFilter, ScoreContentsChildren.ScoreContentNode > typeNodeMap
void unregisterEventListener()
static final Type TSK_DATETIME_PASSWORD_RESET
static final Type TSK_DATETIME_PASSWORD_FAIL
ScoreArtifactNode(BlackboardArtifact artifact)
static String getFilter(ScoreContent.ScoreContentFilter filter, String objIdAlias, String dsIdAlias, long filteringDSObjId)
static final Type TSK_DATETIME_ACCESSED
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)
static final Type TSK_DATETIME_CREATED
final long datasourceObjId
final ScoreContent.ScoreContentFilter filter
static final Logger logger
static String getDataArtifactFilter(ScoreContent.ScoreContentFilter filter, long filteringDsObjId)
T visit(DataSourceFilesNode in)
static final Type TSK_DATETIME
static final Type TSK_DATETIME_RCVD
List< BlackboardAttribute > getAttributes()
List< DataArtifact > getDataArtifactsWhere(String whereClause)
static final Type TSK_DATETIME_START
BLACKBOARD_ARTIFACT_TAG_ADDED
ScoreContentFilter(int id, String name, String displayName)
void addIngestModuleEventListener(final PropertyChangeListener listener)
List< AbstractFile > findAllFilesWhere(String sqlWhereClause)
static final Set< Case.Events > CASE_EVENTS_OF_INTEREST
boolean isRefreshRequired(PropertyChangeEvent evt)
synchronized static Logger getLogger(String name)
static final Type TSK_DATETIME_SENT
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 final Type TSK_DATETIME_DELETED
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)