19 package org.sleuthkit.autopsy.datamodel;
 
   21 import java.beans.PropertyChangeEvent;
 
   22 import java.beans.PropertyChangeListener;
 
   23 import java.sql.ResultSet;
 
   24 import java.sql.SQLException;
 
   25 import java.util.ArrayList;
 
   26 import java.util.Collections;
 
   27 import java.util.Comparator;
 
   28 import java.util.EnumSet;
 
   29 import java.util.HashMap;
 
   30 import java.util.HashSet;
 
   31 import java.util.LinkedHashMap;
 
   32 import java.util.List;
 
   34 import java.util.Observable;
 
   35 import java.util.Observer;
 
   37 import java.util.logging.Level;
 
   38 import org.apache.commons.lang3.StringUtils;
 
   39 import org.openide.nodes.ChildFactory;
 
   40 import org.openide.nodes.Children;
 
   41 import org.openide.nodes.Node;
 
   42 import org.openide.nodes.Sheet;
 
   43 import org.openide.util.Lookup;
 
   44 import org.openide.util.NbBundle;
 
   45 import org.openide.util.WeakListeners;
 
   46 import org.openide.util.lookup.Lookups;
 
   72     @NbBundle.Messages(
"KeywordHits.kwHits.text=Keyword Hits")
 
   73     private static final String 
KEYWORD_HITS = KeywordHits_kwHits_text();
 
   74     @NbBundle.Messages(
"KeywordHits.simpleLiteralSearch.text=Single Literal Keyword Search")
 
   76     @NbBundle.Messages(
"KeywordHits.singleRegexSearch.text=Single Regular Expression Search")
 
   96             + 
"blackboard_attributes.value_int32, " 
   97             + 
"blackboard_artifacts.artifact_obj_id, "  
   98             + 
"blackboard_attributes.attribute_type_id " 
   99             + 
"FROM blackboard_attributes, blackboard_artifacts " 
  100             + 
"WHERE blackboard_attributes.artifact_id = blackboard_artifacts.artifact_id " 
  109         return (instances.size() == 1) && (instances.get(0).equals(DEFAULT_INSTANCE_NAME));
 
  130         this.filteringDSObjId = objId;
 
  144         private final Map<String, Map<String, Map<String, Set<Long>>>> 
topLevelMap = 
new LinkedHashMap<>();
 
  155         List<String> getListNames() {
 
  157                 List<String> names = 
new ArrayList<>(topLevelMap.keySet());
 
  161                 Collections.sort(names, 
new Comparator<String>() {
 
  164                     public int compare(String o1, String o2) {
 
  167                         if (o1.startsWith(
"Single Literal Keyword Search")) {
 
  169                         } 
else if (o2.startsWith(
"Single Literal Keyword Search")) {
 
  171                         } 
else if (o1.startsWith(
"Single Regular Expression Search")) {
 
  173                         } 
else if (o2.startsWith(
"Single Regular Expression Search")) {
 
  176                         return o1.compareTo(o2);
 
  192         List<String> getKeywords(String listName) {
 
  193             List<String> keywords;
 
  195                 keywords = 
new ArrayList<>(topLevelMap.get(listName).keySet());
 
  197             Collections.sort(keywords);
 
  211         List<String> getKeywordInstances(String listName, String keyword) {
 
  212             List<String> instances;
 
  214                 instances = 
new ArrayList<>(topLevelMap.get(listName).get(keyword).keySet());
 
  216             Collections.sort(instances);
 
  231         Set<Long> getArtifactIds(String listName, String keyword, String keywordInstance) {
 
  233                 return topLevelMap.get(listName).get(keyword).get(keywordInstance);
 
  246         void addRegExpToList(Map<String, Map<String, Set<Long>>> listMap, String regExp, String keywordInstance, Long artifactId) {
 
  247             Map<String, Set<Long>> instanceMap = listMap.computeIfAbsent(regExp, r -> 
new LinkedHashMap<>());
 
  249             instanceMap.computeIfAbsent(keywordInstance, ki -> 
new HashSet<>()).add(artifactId);
 
  260         void addNonRegExpMatchToList(Map<String, Map<String, Set<Long>>> listMap, String keyWord, Long artifactId) {
 
  261             Map<String, Set<Long>> instanceMap = listMap.computeIfAbsent(keyWord, k -> 
new LinkedHashMap<>());
 
  264             instanceMap.computeIfAbsent(DEFAULT_INSTANCE_NAME, DIN -> 
new HashSet<>()).add(artifactId);
 
  274         void populateTreeMaps(Map<Long, Map<Long, String>> artifactIds) {
 
  279                 Map<String, Map<String, Map<String, Set<Long>>>> listsMap = 
new LinkedHashMap<>();
 
  282                 Map<String, Map<String, Set<Long>>> literalMap = 
new LinkedHashMap<>();
 
  285                 Map<String, Map<String, Set<Long>>> regexMap = 
new LinkedHashMap<>();
 
  288                 topLevelMap.put(SIMPLE_LITERAL_SEARCH, literalMap);
 
  289                 topLevelMap.put(SIMPLE_REGEX_SEARCH, regexMap);
 
  291                 for (Map.Entry<Long, Map<Long, String>> art : artifactIds.entrySet()) {
 
  292                     long id = art.getKey();
 
  293                     Map<Long, String> attributes = art.getValue();
 
  296                     String listName = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()));
 
  297                     String word = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()));
 
  298                     String reg = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID()));
 
  299                     String kwType = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE.getTypeID()));
 
  301                     if (listName != null) {     
 
  303                         Map<String, Map<String, Set<Long>>> listMap = listsMap.computeIfAbsent(listName, ln -> 
new LinkedHashMap<>());
 
  305                         if (
"1".equals(kwType) || reg == null) {  
 
  312                             word = (reg != null) ? reg : word; 
 
  313                             addNonRegExpMatchToList(listMap, word, 
id);
 
  315                             addRegExpToList(listMap, reg, word, 
id);
 
  318                         if (
"1".equals(kwType) || reg == null) {  
 
  325                             word = (reg != null) ? reg : word; 
 
  326                             addNonRegExpMatchToList(literalMap, word, 
id);
 
  328                             addRegExpToList(regexMap, reg, word, 
id);
 
  332                 topLevelMap.putAll(listsMap);
 
  341             Map<Long, Map<Long, String>> artifactIds = 
new LinkedHashMap<>();
 
  343             if (skCase == null) {
 
  348             if (filteringDSObjId > 0) {
 
  349                 queryStr += 
"  AND blackboard_artifacts.data_source_obj_id = " + 
filteringDSObjId;
 
  353                 ResultSet resultSet = dbQuery.getResultSet();
 
  354                 while (resultSet.next()) {
 
  355                     long artifactObjId = resultSet.getLong(
"artifact_obj_id"); 
 
  356                     long typeId = resultSet.getLong(
"attribute_type_id"); 
 
  357                     String valueStr = resultSet.getString(
"value_text"); 
 
  360                     Map<Long, String> attributesByTypeMap = artifactIds.computeIfAbsent(artifactObjId, ai -> 
new LinkedHashMap<>());
 
  361                     if (StringUtils.isNotEmpty(valueStr)) {
 
  362                         attributesByTypeMap.put(typeId, valueStr);
 
  365                         Long valueLong = resultSet.getLong(
"value_int32");
 
  366                         attributesByTypeMap.put(typeId, valueLong.toString());
 
  370                 logger.log(Level.WARNING, 
"SQL Exception occurred: ", ex); 
 
  373             populateTreeMaps(artifactIds);
 
  379         return visitor.
visit(
this);
 
  387                     Lookups.singleton(KEYWORD_HITS),
 
  393             this.setIconBaseWithExtension(
"org/sleuthkit/autopsy/images/keyword_hits.png"); 
 
  403             return visitor.
visit(
this);
 
  407         @NbBundle.Messages({
"KeywordHits.createSheet.name.name=Name",
 
  408             "KeywordHits.createSheet.name.displayName=Name",
 
  409             "KeywordHits.createSheet.name.desc=no description"})
 
  411             Sheet sheet = super.createSheet();
 
  412             Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
 
  413             if (sheetSet == null) {
 
  414                 sheetSet = Sheet.createPropertiesSet();
 
  419                     KeywordHits_createSheet_name_name(),
 
  420                     KeywordHits_createSheet_name_displayName(),
 
  421                     KeywordHits_createSheet_name_desc(),
 
  429             return getClass().getName();
 
  437             keywordResults.addObserver(
this);
 
  443             keywordResults.deleteObserver(
this);
 
  447         public void update(Observable o, Object arg) {
 
  457         private final PropertyChangeListener 
pcl = 
new PropertyChangeListener() {
 
  459             public void propertyChange(PropertyChangeEvent evt) {
 
  460                 String eventType = evt.getPropertyName();
 
  498                         && evt.getNewValue() == null) {
 
  510         private final PropertyChangeListener 
weakPcl = WeakListeners.propertyChange(pcl, null);
 
  531             list.addAll(keywordResults.getListNames());
 
  537             return new ListNode(key);
 
  546             super(children, lookup);
 
  556             return getClass().getName();
 
  560         public void update(Observable o, Object arg) {
 
  564         final void updateDisplayName() {
 
  565             super.setDisplayName(displayName + 
" (" + countTotalDescendants() + 
")");
 
  568         abstract int countTotalDescendants();
 
  575     class ListNode 
extends KWHitsNodeBase {
 
  577         private final String listName;
 
  579         private ListNode(String listName) {
 
  580             super(Children.create(
new TermFactory(listName), 
true), Lookups.singleton(listName), listName);
 
  581             super.setName(listName);
 
  582             this.setIconBaseWithExtension(
"org/sleuthkit/autopsy/images/keyword_hits.png"); 
 
  583             this.listName = listName;
 
  585             keywordResults.addObserver(
this);
 
  589         public int countTotalDescendants() {
 
  590             int totalDescendants = 0;
 
  592             for (String word : keywordResults.getKeywords(listName)) {
 
  593                 for (String instance : keywordResults.getKeywordInstances(listName, word)) {
 
  594                     Set<Long> ids = keywordResults.getArtifactIds(listName, word, instance);
 
  595                     totalDescendants += ids.size();
 
  598             return totalDescendants;
 
  602         @NbBundle.Messages({
"KeywordHits.createSheet.listName.name=List Name",
 
  603             "KeywordHits.createSheet.listName.displayName=List Name",
 
  604             "KeywordHits.createSheet.listName.desc=no description",
 
  605             "KeywordHits.createSheet.numChildren.name=Number of Children",
 
  606             "KeywordHits.createSheet.numChildren.displayName=Number of Children",
 
  607             "KeywordHits.createSheet.numChildren.desc=no description"})
 
  608         protected Sheet createSheet() {
 
  609             Sheet sheet = super.createSheet();
 
  610             Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
 
  611             if (sheetSet == null) {
 
  612                 sheetSet = Sheet.createPropertiesSet();
 
  616             sheetSet.put(
new NodeProperty<>(
 
  617                     KeywordHits_createSheet_listName_name(),
 
  618                     KeywordHits_createSheet_listName_displayName(),
 
  619                     KeywordHits_createSheet_listName_desc(),
 
  622             sheetSet.put(
new NodeProperty<>(
 
  623                     KeywordHits_createSheet_numChildren_name(),
 
  624                     KeywordHits_createSheet_numChildren_displayName(),
 
  625                     KeywordHits_createSheet_numChildren_desc(),
 
  626                     keywordResults.getKeywords(listName).size()));
 
  632         public boolean isLeafTypeNode() {
 
  637         public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
 
  638             return visitor.visit(
this);
 
  656             list.addAll(keywordResults.getKeywords(setName));
 
  662             return new TermNode(setName, key);
 
  676     ChildFactory<?> createChildFactory(String setName, String keyword) {
 
  678             return new HitsFactory(setName, keyword, DEFAULT_INSTANCE_NAME);
 
  680             return new RegExpInstancesFactory(setName, keyword);
 
  687     class TermNode 
extends KWHitsNodeBase {
 
  689         private final String setName;
 
  690         private final String keyword;
 
  692         private TermNode(String setName, String keyword) {
 
  693             super(Children.create(createChildFactory(setName, keyword), 
true), Lookups.singleton(keyword), keyword);
 
  702             super.setName(setName + 
"_" + keyword);
 
  703             this.setName = setName;
 
  704             this.keyword = keyword;
 
  705             this.setIconBaseWithExtension(
"org/sleuthkit/autopsy/images/keyword_hits.png"); 
 
  707             keywordResults.addObserver(
this);
 
  711         int countTotalDescendants() {
 
  712             return keywordResults.getKeywordInstances(setName, keyword).stream()
 
  713                     .mapToInt(instance -> keywordResults.getArtifactIds(setName, keyword, instance).size())
 
  718         public boolean isLeafTypeNode() {
 
  724         public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
 
  725             return visitor.visit(
this);
 
  729         @NbBundle.Messages({
"KeywordHits.createSheet.filesWithHits.name=Files with Hits",
 
  730             "KeywordHits.createSheet.filesWithHits.displayName=Files with Hits",
 
  731             "KeywordHits.createSheet.filesWithHits.desc=no description"})
 
  732         protected Sheet createSheet() {
 
  733             Sheet sheet = super.createSheet();
 
  734             Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
 
  735             if (sheetSet == null) {
 
  736                 sheetSet = Sheet.createPropertiesSet();
 
  739             sheetSet.put(
new NodeProperty<>(
 
  740                     KeywordHits_createSheet_listName_name(),
 
  741                     KeywordHits_createSheet_listName_displayName(),
 
  742                     KeywordHits_createSheet_listName_desc(),
 
  745             sheetSet.put(
new NodeProperty<>(
 
  746                     KeywordHits_createSheet_filesWithHits_name(),
 
  747                     KeywordHits_createSheet_filesWithHits_displayName(),
 
  748                     KeywordHits_createSheet_filesWithHits_desc(),
 
  749                     countTotalDescendants()));
 
  772             list.addAll(keywordResults.getKeywordInstances(setName, keyword));
 
  778             return new RegExpInstanceNode(setName, keyword, key);
 
  785     class RegExpInstanceNode 
extends KWHitsNodeBase {
 
  787         private final String setName;
 
  788         private final String keyword;
 
  789         private final String instance;
 
  791         private RegExpInstanceNode(String setName, String keyword, String instance) {
 
  792             super(Children.create(
new HitsFactory(setName, keyword, instance), 
true), Lookups.singleton(instance), instance);
 
  801             super.setName(setName + 
"_" + keyword + 
"_" + instance);
 
  802             this.setName = setName;
 
  803             this.keyword = keyword;
 
  804             this.instance = instance;
 
  805             this.setIconBaseWithExtension(
"org/sleuthkit/autopsy/images/keyword_hits.png"); 
 
  807             keywordResults.addObserver(
this);
 
  811         int countTotalDescendants() {
 
  812             return keywordResults.getArtifactIds(setName, keyword, instance).size();
 
  816         public boolean isLeafTypeNode() {
 
  821         public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
 
  822             return visitor.visit(
this);
 
  826         protected Sheet createSheet() {
 
  827             Sheet sheet = super.createSheet();
 
  828             Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
 
  829             if (sheetSet == null) {
 
  830                 sheetSet = Sheet.createPropertiesSet();
 
  834             sheetSet.put(
new NodeProperty<>(
 
  835                     KeywordHits_createSheet_listName_name(),
 
  836                     KeywordHits_createSheet_listName_displayName(),
 
  837                     KeywordHits_createSheet_listName_desc(),
 
  840             sheetSet.put(
new NodeProperty<>(
 
  841                     KeywordHits_createSheet_filesWithHits_name(),
 
  842                     KeywordHits_createSheet_filesWithHits_displayName(),
 
  843                     KeywordHits_createSheet_filesWithHits_desc(),
 
  844                     keywordResults.getArtifactIds(setName, keyword, instance).size()));
 
  858     @NbBundle.Messages({
"KeywordHits.createNodeForKey.modTime.name=ModifiedTime",
 
  859         "KeywordHits.createNodeForKey.modTime.displayName=Modified Time",
 
  860         "KeywordHits.createNodeForKey.modTime.desc=Modified Time",
 
  861         "KeywordHits.createNodeForKey.accessTime.name=AccessTime",
 
  862         "KeywordHits.createNodeForKey.accessTime.displayName=Access Time",
 
  863         "KeywordHits.createNodeForKey.accessTime.desc=Access Time",
 
  864         "KeywordHits.createNodeForKey.chgTime.name=ChangeTime",
 
  865         "KeywordHits.createNodeForKey.chgTime.displayName=Change Time",
 
  866         "KeywordHits.createNodeForKey.chgTime.desc=Change Time"})
 
  868         if (skCase == null) {
 
  881                 logger.log(Level.SEVERE, 
"TskCoreException while constructing BlackboardArtifact Node from KeywordHitsKeywordChildren", ex); 
 
  894                 KeywordHits_createNodeForKey_modTime_name(),
 
  895                 KeywordHits_createNodeForKey_modTime_displayName(),
 
  896                 KeywordHits_createNodeForKey_modTime_desc(),
 
  899                 KeywordHits_createNodeForKey_accessTime_name(),
 
  900                 KeywordHits_createNodeForKey_accessTime_displayName(),
 
  901                 KeywordHits_createNodeForKey_accessTime_desc(),
 
  904                 KeywordHits_createNodeForKey_chgTime_name(),
 
  905                 KeywordHits_createNodeForKey_chgTime_displayName(),
 
  906                 KeywordHits_createNodeForKey_chgTime_desc(),
 
  919         private final Map<Long, AnalysisResult> 
artifactHits = 
new HashMap<>();
 
  921         private HitsFactory(String setName, String keyword, String instance) {
 
  928             super(setName + 
"_" + keyword + (DEFAULT_INSTANCE_NAME.equals(instance) ? 
"" : 
"_" + 
instance));
 
  936             if (skCase != null) {
 
  937                 keywordResults.getArtifactIds(setName, keyword, instance).forEach((
id) -> {
 
  939                         if (!artifactHits.containsKey(
id)) {
 
  944                             artifactHits.put(
id, art);
 
  947                         logger.log(Level.SEVERE, 
"TSK Exception occurred", ex); 
 
  951                 return new ArrayList<>(artifactHits.values());
 
  953             return Collections.emptyList();
 
  963             keywordResults.addObserver(
this);
 
  968             keywordResults.deleteObserver(
this);
 
  972         public void update(Observable o, Object arg) {
 
final PropertyChangeListener pcl
static boolean isOnlyDefaultInstance(List< String > instances)
static final String KEYWORD_HITS
BlackboardArtifact.Type getBlackboardArtifactType()
void removeIngestModuleEventListener(final PropertyChangeListener listener)
AnalysisResult getAnalysisResultById(long artifactObjId)
Node createNodeForKey(String key)
final long filteringDSObjId
static synchronized IngestManager getInstance()
void update(Observable o, Object arg)
final KeywordResults keywordResults
Node createNodeForKey(AnalysisResult art)
Blackboard getBlackboard()
static final Type TSK_KEYWORD_HIT
static String getFormattedTime(long epochTime)
static final String SIMPLE_REGEX_SEARCH
TermFactory(String setName)
final Map< String, Map< String, Map< String, Set< Long > > > > topLevelMap
final Map< Long, AnalysisResult > artifactHits
BlackboardArtifactNode createBlackboardArtifactNode(AnalysisResult art)
static final Set< IngestManager.IngestJobEvent > INGEST_JOB_EVENTS_OF_INTEREST
AbstractFile getAbstractFileById(long id)
boolean createKeys(List< String > list)
void removeIngestJobEventListener(final PropertyChangeListener listener)
KWHitsNodeBase(Children children)
boolean createKeys(List< String > list)
void addNodeProperty(NodeProperty<?> property)
boolean createKeys(List< String > list)
void update(Observable o, Object arg)
RegExpInstancesFactory(String setName, String keyword)
void addIngestJobEventListener(final PropertyChangeListener listener)
static final String DEFAULT_INSTANCE_NAME
Node createNodeForKey(String key)
final PropertyChangeListener weakPcl
T visit(DataSourceFilesNode in)
static final Logger logger
List< BlackboardAttribute > getAttributes()
Node createNodeForKey(String key)
static final String KEYWORD_HIT_ATTRIBUTES_QUERY
void addIngestModuleEventListener(final PropertyChangeListener listener)
KeywordHits(SleuthkitCase skCase, long objId)
synchronized static Logger getLogger(String name)
static final Set< IngestManager.IngestModuleEvent > INGEST_MODULE_EVENTS_OF_INTEREST
static Case getCurrentCaseThrows()
static void addEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
void update(Observable o, Object arg)
final long filteringDSObjId
HitsFactory(String setName, String keyword, String instance)
KWHitsNodeBase(Children children, Lookup lookup, String displayName)
static void removeEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
static final String SIMPLE_LITERAL_SEARCH
List< AnalysisResult > makeKeys()
CaseDbQuery executeQuery(String query)