Autopsy  4.16.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
SearchFiltering.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2019-2020 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  */
19 package org.sleuthkit.autopsy.discovery.search;
20 
21 import java.text.SimpleDateFormat;
29 import org.sleuthkit.datamodel.AbstractFile;
30 import org.sleuthkit.datamodel.DataSource;
31 import org.sleuthkit.datamodel.SleuthkitCase;
32 import org.sleuthkit.datamodel.TagName;
33 import org.sleuthkit.datamodel.TskCoreException;
34 import java.util.ArrayList;
35 import java.util.Arrays;
36 import java.util.Date;
37 import java.util.List;
38 import java.util.Locale;
39 import java.util.StringJoiner;
40 import java.util.concurrent.TimeUnit;
41 import java.util.stream.Collectors;
42 import org.openide.util.NbBundle;
43 import org.sleuthkit.datamodel.BlackboardArtifact;
44 import org.sleuthkit.datamodel.BlackboardAttribute;
45 import org.sleuthkit.datamodel.TskData;
47 import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
48 
52 public class SearchFiltering {
53 
64  static List<Result> runQueries(List<AbstractFilter> filters, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException {
65  if (caseDb == null) {
66  throw new DiscoveryException("Case DB parameter is null"); // NON-NLS
67  }
68  // Combine all the SQL queries from the filters into one query
69  String combinedQuery = "";
70  for (AbstractFilter filter : filters) {
71  if (!filter.getWhereClause().isEmpty()) {
72  if (!combinedQuery.isEmpty()) {
73  combinedQuery += " AND "; // NON-NLS
74  }
75  combinedQuery += "(" + filter.getWhereClause() + ")"; // NON-NLS
76  }
77  }
78 
79  if (combinedQuery.isEmpty()) {
80  // The file search filter is required, so this should never be empty.
81  throw new DiscoveryException("Selected filters do not include a case database query");
82  }
83  try {
84  return getResultList(filters, combinedQuery, caseDb, centralRepoDb);
85  } catch (TskCoreException ex) {
86  throw new DiscoveryException("Error querying case database", ex); // NON-NLS
87  }
88  }
89 
104  private static List<Result> getResultList(List<AbstractFilter> filters, String combinedQuery, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws TskCoreException, DiscoveryException {
105  // Get all matching abstract files
106  List<Result> resultList = new ArrayList<>();
107  List<AbstractFile> sqlResults = caseDb.findAllFilesWhere(combinedQuery);
108 
109  // If there are no results, return now
110  if (sqlResults.isEmpty()) {
111  return resultList;
112  }
113 
114  // Wrap each result in a ResultFile
115  for (AbstractFile abstractFile : sqlResults) {
116  resultList.add(new ResultFile(abstractFile));
117  }
118 
119  // Now run any non-SQL filters.
120  for (AbstractFilter filter : filters) {
121  if (filter.useAlternateFilter()) {
122  resultList = filter.applyAlternateFilter(resultList, caseDb, centralRepoDb);
123  }
124  // There are no matches for the filters run so far, so return
125  if (resultList.isEmpty()) {
126  return resultList;
127  }
128  }
129  return resultList;
130  }
131 
136  public static class ArtifactDateRangeFilter extends AbstractFilter {
137 
138  private final Long startDate;
139  private final Long endDate;
140 
141  // Attributes to search for date
142  private static List<BlackboardAttribute.ATTRIBUTE_TYPE> dateAttributes
143  = Arrays.asList(
144  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME,
145  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
146  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED
147  );
148 
155  public ArtifactDateRangeFilter(Long startDate, Long endDate) {
156  this.startDate = startDate;
157  this.endDate = endDate;
158  }
159 
164  static String createAttributeTypeClause() {
165  StringJoiner joiner = new StringJoiner(",");
166  for (BlackboardAttribute.ATTRIBUTE_TYPE type : dateAttributes) {
167  joiner.add("\'" + type.getTypeID() + "\'");
168  }
169  return "attribute_type_id IN (" + joiner.toString() + ")";
170  }
171 
172  @Override
173  public String getWhereClause() {
174  return createAttributeTypeClause()
175  + " AND (value_int64 BETWEEN " + startDate + " AND " + endDate + ")";
176  }
177 
178  @NbBundle.Messages({"SearchFiltering.dateRangeFilter.lable=Activity date ",
179  "# {0} - startDate",
180  "SearchFiltering.dateRangeFilter.after=after: {0}",
181  "# {0} - endDate",
182  "SearchFiltering.dateRangeFilter.before=before: {0}",
183  "SearchFiltering.dateRangeFilter.and= and "})
184  @Override
185  public String getDesc() {
186  String desc = ""; // NON-NLS
187  if (startDate > 0 ) {
188  desc += Bundle.SearchFiltering_dateRangeFilter_after(new SimpleDateFormat("yyyy/MM/dd", Locale.getDefault()).format(new Date(TimeUnit.SECONDS.toMillis(startDate))));
189  }
190  if (endDate < 10000000000L) { //arbitrary time sometime in the 23rd century to check that they specified a date and the max date isn't being used
191  if (!desc.isEmpty()) {
192  desc += Bundle.SearchFiltering_dateRangeFilter_and();
193  }
194  desc += Bundle.SearchFiltering_dateRangeFilter_before(new SimpleDateFormat("yyyy/MM/dd", Locale.getDefault()).format(new Date(TimeUnit.SECONDS.toMillis(endDate))));
195  }
196  if (!desc.isEmpty()){
197  desc = Bundle.SearchFiltering_dateRangeFilter_lable()+desc;
198  }
199  return desc;
200  }
201  }
202 
206  public static class ArtifactTypeFilter extends AbstractFilter {
207 
208  private final List<ARTIFACT_TYPE> types;
209 
216  public ArtifactTypeFilter(List<ARTIFACT_TYPE> types) {
217  this.types = types;
218  }
219 
220  @Override
221  public String getWhereClause() {
222  StringJoiner joiner = new StringJoiner(",");
223  for (ARTIFACT_TYPE type : types) {
224  joiner.add("\'" + type.getTypeID() + "\'");
225  }
226 
227  return "artifact_type_id IN (" + joiner + ")";
228  }
229 
230  @NbBundle.Messages({"# {0} - artifactTypes",
231  "SearchFiltering.artifactTypeFilter.desc=Result type(s): {0}",
232  "SearchFiltering.artifactTypeFilter.or=, "})
233  @Override
234  public String getDesc() {
235  String desc = ""; // NON-NLS
236  for (ARTIFACT_TYPE type : types) {
237  if (!desc.isEmpty()) {
238  desc += Bundle.SearchFiltering_artifactTypeFilter_or();
239  }
240  desc += type.getDisplayName();
241  }
242  desc = Bundle.SearchFiltering_artifactTypeFilter_desc(desc);
243  return desc;
244  }
245 
246  }
247 
251  public static class SizeFilter extends AbstractFilter {
252 
253  private final List<FileSize> fileSizes;
254 
260  public SizeFilter(List<FileSize> fileSizes) {
261  this.fileSizes = fileSizes;
262  }
263 
264  @Override
265  public String getWhereClause() {
266  String queryStr = ""; // NON-NLS
267  for (FileSize size : fileSizes) {
268  if (!queryStr.isEmpty()) {
269  queryStr += " OR "; // NON-NLS
270  }
271  if (size.getMaxBytes() != FileSize.NO_MAXIMUM) {
272  queryStr += "(size > \'" + size.getMinBytes() + "\' AND size <= \'" + size.getMaxBytes() + "\')"; // NON-NLS
273  } else {
274  queryStr += "(size >= \'" + size.getMinBytes() + "\')"; // NON-NLS
275  }
276  }
277  return queryStr;
278  }
279 
280  @NbBundle.Messages({
281  "# {0} - filters",
282  "SearchFiltering.SizeFilter.desc=Size(s): {0}",
283  "SearchFiltering.SizeFilter.or=, "})
284  @Override
285  public String getDesc() {
286  String desc = ""; // NON-NLS
287  for (FileSize size : fileSizes) {
288  if (!desc.isEmpty()) {
289  desc += Bundle.SearchFiltering_SizeFilter_or();
290  }
291  desc += size.getSizeGroup();
292  }
293  desc = Bundle.SearchFiltering_SizeFilter_desc(desc);
294  return desc;
295  }
296  }
297 
302  public static class ParentSearchTerm {
303 
304  private final String searchStr;
305  private final boolean fullPath;
306  private final boolean included;
307 
317  public ParentSearchTerm(String searchStr, boolean isFullPath, boolean isIncluded) {
318  this.searchStr = searchStr;
319  this.fullPath = isFullPath;
320  this.included = isIncluded;
321  }
322 
328  public String getSQLForTerm() {
329  // TODO - these should really be prepared statements
330  if (isIncluded()) {
331  if (isFullPath()) {
332  return "parent_path=\'" + getSearchStr() + "\'"; // NON-NLS
333  } else {
334  return "parent_path LIKE \'%" + getSearchStr() + "%\'"; // NON-NLS
335  }
336  } else {
337  if (isFullPath()) {
338  return "parent_path!=\'" + getSearchStr() + "\'"; // NON-NLS
339  } else {
340  return "parent_path NOT LIKE \'%" + getSearchStr() + "%\'"; // NON-NLS
341  }
342  }
343  }
344 
345  @NbBundle.Messages({
346  "SearchFiltering.ParentSearchTerm.fullString= (exact)",
347  "SearchFiltering.ParentSearchTerm.subString= (substring)",
348  "SearchFiltering.ParentSearchTerm.includeString= (include)",
349  "SearchFiltering.ParentSearchTerm.excludeString= (exclude)",})
350  @Override
351  public String toString() {
352  String returnString = getSearchStr();
353  if (isFullPath()) {
354  returnString += Bundle.SearchFiltering_ParentSearchTerm_fullString();
355  } else {
356  returnString += Bundle.SearchFiltering_ParentSearchTerm_subString();
357  }
358  if (isIncluded()) {
359  returnString += Bundle.SearchFiltering_ParentSearchTerm_includeString();
360  } else {
361  returnString += Bundle.SearchFiltering_ParentSearchTerm_excludeString();
362  }
363  return returnString;
364  }
365 
373  public boolean isFullPath() {
374  return fullPath;
375  }
376 
384  public boolean isIncluded() {
385  return included;
386  }
387 
393  public String getSearchStr() {
394  return searchStr;
395  }
396  }
397 
401  public static class ParentFilter extends AbstractFilter {
402 
403  private final List<ParentSearchTerm> parentSearchTerms;
404 
410  public ParentFilter(List<ParentSearchTerm> parentSearchTerms) {
411  this.parentSearchTerms = parentSearchTerms;
412  }
413 
414  @Override
415  public String getWhereClause() {
416  String includeQueryStr = ""; // NON-NLS
417  String excludeQueryStr = "";
418  for (ParentSearchTerm searchTerm : parentSearchTerms) {
419  if (searchTerm.isIncluded()) {
420  if (!includeQueryStr.isEmpty()) {
421  includeQueryStr += " OR "; // NON-NLS
422  }
423  includeQueryStr += searchTerm.getSQLForTerm();
424  } else {
425  if (!excludeQueryStr.isEmpty()) {
426  excludeQueryStr += " AND "; // NON-NLS
427  }
428  excludeQueryStr += searchTerm.getSQLForTerm();
429  }
430  }
431  if (!includeQueryStr.isEmpty()) {
432  includeQueryStr = "(" + includeQueryStr + ")";
433  }
434  if (!excludeQueryStr.isEmpty()) {
435  excludeQueryStr = "(" + excludeQueryStr + ")";
436  }
437  if (includeQueryStr.isEmpty() || excludeQueryStr.isEmpty()) {
438  return includeQueryStr + excludeQueryStr;
439  } else {
440  return includeQueryStr + " AND " + excludeQueryStr;
441  }
442  }
443 
444  @NbBundle.Messages({
445  "# {0} - filters",
446  "SearchFiltering.ParentFilter.desc=Paths matching: {0}",
447  "SearchFiltering.ParentFilter.or=, ",
448  "SearchFiltering.ParentFilter.exact=(exact match)",
449  "SearchFiltering.ParentFilter.substring=(substring)",
450  "SearchFiltering.ParentFilter.included=(included)",
451  "SearchFiltering.ParentFilter.excluded=(excluded)"})
452  @Override
453  public String getDesc() {
454  String desc = ""; // NON-NLS
455  for (ParentSearchTerm searchTerm : parentSearchTerms) {
456  if (!desc.isEmpty()) {
457  desc += Bundle.SearchFiltering_ParentFilter_or();
458  }
459  if (searchTerm.isFullPath()) {
460  desc += searchTerm.getSearchStr() + Bundle.SearchFiltering_ParentFilter_exact();
461  } else {
462  desc += searchTerm.getSearchStr() + Bundle.SearchFiltering_ParentFilter_substring();
463  }
464  if (searchTerm.isIncluded()) {
465  desc += Bundle.SearchFiltering_ParentFilter_included();
466  } else {
467  desc += Bundle.SearchFiltering_ParentFilter_excluded();
468  }
469  }
470  desc = Bundle.SearchFiltering_ParentFilter_desc(desc);
471  return desc;
472  }
473  }
474 
478  public static class DataSourceFilter extends AbstractFilter {
479 
480  private final List<DataSource> dataSources;
481 
487  public DataSourceFilter(List<DataSource> dataSources) {
488  this.dataSources = dataSources;
489  }
490 
491  @Override
492  public String getWhereClause() {
493  String queryStr = ""; // NON-NLS
494  for (DataSource ds : dataSources) {
495  if (!queryStr.isEmpty()) {
496  queryStr += ","; // NON-NLS
497  }
498  queryStr += "\'" + ds.getId() + "\'"; // NON-NLS
499  }
500  queryStr = "data_source_obj_id IN (" + queryStr + ")"; // NON-NLS
501  return queryStr;
502  }
503 
504  @NbBundle.Messages({
505  "# {0} - filters",
506  "SearchFiltering.DataSourceFilter.desc=Data source(s): {0}",
507  "SearchFiltering.DataSourceFilter.or=, ",
508  "# {0} - Data source name",
509  "# {1} - Data source ID",
510  "SearchFiltering.DataSourceFilter.datasource={0}({1})",})
511  @Override
512  public String getDesc() {
513  String desc = ""; // NON-NLS
514  for (DataSource ds : dataSources) {
515  if (!desc.isEmpty()) {
516  desc += Bundle.SearchFiltering_DataSourceFilter_or();
517  }
518  desc += Bundle.SearchFiltering_DataSourceFilter_datasource(ds.getName(), ds.getId());
519  }
520  desc = Bundle.SearchFiltering_DataSourceFilter_desc(desc);
521  return desc;
522  }
523  }
524 
529  public static class KeywordListFilter extends AbstractFilter {
530 
531  private final List<String> listNames;
532 
538  public KeywordListFilter(List<String> listNames) {
539  this.listNames = listNames;
540  }
541 
542  @Override
543  public String getWhereClause() {
544  String keywordListPart = concatenateNamesForSQL(listNames);
545 
546  String queryStr = "(obj_id IN (SELECT obj_id from blackboard_artifacts WHERE artifact_id IN "
547  + "(SELECT artifact_id FROM blackboard_attributes WHERE artifact_type_id = 9 AND attribute_type_ID = 37 "
548  + "AND (" + keywordListPart + "))))"; // NON-NLS
549 
550  return queryStr;
551  }
552 
553  @NbBundle.Messages({
554  "# {0} - filters",
555  "SearchFiltering.KeywordListFilter.desc=Keywords in list(s): {0}",})
556  @Override
557  public String getDesc() {
558  return Bundle.SearchFiltering_KeywordListFilter_desc(concatenateSetNamesForDisplay(listNames));
559  }
560  }
561 
565  public static class FileTypeFilter extends AbstractFilter {
566 
567  private final List<Type> categories;
568 
574  public FileTypeFilter(List<Type> categories) {
575  this.categories = categories;
576  }
577 
583  public FileTypeFilter(Type category) {
584  this.categories = new ArrayList<>();
585  this.categories.add(category);
586  }
587 
588  @Override
589  public String getWhereClause() {
590  String queryStr = ""; // NON-NLS
591  for (Type cat : categories) {
592  for (String type : cat.getMediaTypes()) {
593  if (!queryStr.isEmpty()) {
594  queryStr += ","; // NON-NLS
595  }
596  queryStr += "\'" + type + "\'"; // NON-NLS
597  }
598  }
599  queryStr = "mime_type IN (" + queryStr + ")"; // NON-NLS
600  return queryStr;
601  }
602 
603  @NbBundle.Messages({
604  "# {0} - filters",
605  "SearchFiltering.FileTypeFilter.desc=Type: {0}",
606  "SearchFiltering.FileTypeFilter.or=, ",})
607  @Override
608  public String getDesc() {
609  String desc = "";
610  for (Type cat : categories) {
611  if (!desc.isEmpty()) {
612  desc += Bundle.SearchFiltering_FileTypeFilter_or();
613  }
614  desc += cat.toString();
615  }
616  desc = Bundle.SearchFiltering_FileTypeFilter_desc(desc);
617  return desc;
618  }
619  }
620 
624  public static class FrequencyFilter extends AbstractFilter {
625 
626  private final List<Frequency> frequencies;
627 
633  public FrequencyFilter(List<Frequency> frequencies) {
634  this.frequencies = frequencies;
635  }
636 
637  @Override
638  public String getWhereClause() {
639  // Since this relies on the central repository database, there is no
640  // query on the case database.
641  return ""; // NON-NLS
642  }
643 
644  @Override
645  public boolean useAlternateFilter() {
646  return true;
647  }
648 
649  @Override
650  public List<Result> applyAlternateFilter(List<Result> currentResults, SleuthkitCase caseDb,
651  CentralRepository centralRepoDb) throws DiscoveryException {
652  // Set the frequency for each file
654  freqAttr.addAttributeToResults(currentResults, caseDb, centralRepoDb);
655 
656  // If the frequency matches the filter, add the file to the results
657  List<Result> frequencyResults = new ArrayList<>();
658  for (Result file : currentResults) {
659  if (frequencies.contains(file.getFrequency())) {
660  frequencyResults.add(file);
661  }
662  }
663  return frequencyResults;
664  }
665 
666  @NbBundle.Messages({
667  "# {0} - filters",
668  "SearchFiltering.FrequencyFilter.desc=Past occurrences: {0}",
669  "SearchFiltering.FrequencyFilter.or=, ",})
670  @Override
671  public String getDesc() {
672  String desc = ""; // NON-NLS
673  for (Frequency freq : frequencies) {
674  if (!desc.isEmpty()) {
675  desc += Bundle.SearchFiltering_FrequencyFilter_or();
676  }
677  desc += freq.toString();
678  }
679  return Bundle.SearchFiltering_FrequencyFilter_desc(desc);
680  }
681  }
682 
687  public static class HashSetFilter extends AbstractFilter {
688 
689  private final List<String> setNames;
690 
696  public HashSetFilter(List<String> setNames) {
697  this.setNames = setNames;
698  }
699 
700  @Override
701  public String getWhereClause() {
702  String hashSetPart = concatenateNamesForSQL(setNames);
703 
704  String queryStr = "(obj_id IN (SELECT obj_id from blackboard_artifacts WHERE artifact_id IN "
705  + "(SELECT artifact_id FROM blackboard_attributes WHERE artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()
706  + " AND attribute_type_ID = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + " "
707  + "AND (" + hashSetPart + "))))"; // NON-NLS
708 
709  return queryStr;
710  }
711 
712  @NbBundle.Messages({
713  "# {0} - filters",
714  "FileSearchFiltering.HashSetFilter.desc=Hash set hits in set(s): {0}",})
715  @Override
716  public String getDesc() {
717  return Bundle.FileSearchFiltering_HashSetFilter_desc(concatenateSetNamesForDisplay(setNames));
718  }
719  }
720 
725  public static class InterestingFileSetFilter extends AbstractFilter {
726 
727  private final List<String> setNames;
728 
734  public InterestingFileSetFilter(List<String> setNames) {
735  this.setNames = setNames;
736  }
737 
738  @Override
739  public String getWhereClause() {
740  String intItemSetPart = concatenateNamesForSQL(setNames);
741 
742  String queryStr = "(obj_id IN (SELECT obj_id from blackboard_artifacts WHERE artifact_id IN "
743  + "(SELECT artifact_id FROM blackboard_attributes WHERE artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID()
744  + " AND attribute_type_ID = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + " "
745  + "AND (" + intItemSetPart + "))))"; // NON-NLS
746 
747  return queryStr;
748  }
749 
750  @NbBundle.Messages({
751  "# {0} - filters",
752  "SearchFiltering.InterestingItemSetFilter.desc=Interesting item hits in set(s): {0}",})
753  @Override
754  public String getDesc() {
755  return Bundle.SearchFiltering_InterestingItemSetFilter_desc(concatenateSetNamesForDisplay(setNames));
756  }
757  }
758 
763  public static class ObjectDetectionFilter extends AbstractFilter {
764 
765  private final List<String> typeNames;
766 
772  public ObjectDetectionFilter(List<String> typeNames) {
773  this.typeNames = typeNames;
774  }
775 
776  @Override
777  public String getWhereClause() {
778  String objTypePart = concatenateNamesForSQL(typeNames);
779 
780  String queryStr = "(obj_id IN (SELECT obj_id from blackboard_artifacts WHERE artifact_id IN "
781  + "(SELECT artifact_id FROM blackboard_attributes WHERE artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID()
782  + " AND attribute_type_ID = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION.getTypeID() + " "
783  + "AND (" + objTypePart + "))))"; // NON-NLS
784 
785  return queryStr;
786  }
787 
788  @NbBundle.Messages({
789  "# {0} - filters",
790  "SearchFiltering.ObjectDetectionFilter.desc=Objects detected in set(s): {0}",})
791  @Override
792  public String getDesc() {
793  return Bundle.SearchFiltering_ObjectDetectionFilter_desc(concatenateSetNamesForDisplay(typeNames));
794  }
795  }
796 
801  public static class ScoreFilter extends AbstractFilter {
802 
803  private final List<Score> scores;
804 
810  public ScoreFilter(List<Score> scores) {
811  this.scores = scores;
812  }
813 
814  @Override
815  public String getWhereClause() {
816 
817  // Current algorithm:
818  // "Notable" if the file is a match for a notable hashset or has been tagged with a notable tag.
819  // "Interesting" if the file has an interesting item match or has been tagged with a non-notable tag.
820  String hashsetQueryPart = "";
821  String tagQueryPart = "";
822  String intItemQueryPart = "";
823 
824  if (scores.contains(Score.NOTABLE)) {
825  // do hashset
826  hashsetQueryPart = " (known = " + TskData.FileKnown.BAD.getFileKnownValue() + ") ";
827  }
828 
829  if (scores.contains(Score.INTERESTING)) {
830  // Matches interesting item artifact
831  intItemQueryPart = " (obj_id IN (SELECT obj_id from blackboard_artifacts WHERE artifact_type_id = "
832  + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() + ")) ";
833  }
834 
835  if (scores.contains(Score.NOTABLE) && scores.contains(Score.INTERESTING)) {
836  // Any tag will work
837  tagQueryPart = "(obj_id IN (SELECT obj_id FROM content_tags))";
838  } else if (scores.contains(Score.NOTABLE)) {
839  // Notable tags
840  tagQueryPart = "(obj_id IN (SELECT obj_id FROM content_tags WHERE tag_name_id IN (SELECT tag_name_id FROM tag_names WHERE knownStatus = "
841  + TskData.FileKnown.BAD.getFileKnownValue() + ")))";
842  } else if (scores.contains(Score.INTERESTING)) {
843  // Non-notable tags
844  tagQueryPart = "(obj_id IN (SELECT obj_id FROM content_tags WHERE tag_name_id IN (SELECT tag_name_id FROM tag_names WHERE knownStatus != "
845  + TskData.FileKnown.BAD.getFileKnownValue() + ")))";
846  }
847 
848  String queryStr = hashsetQueryPart;
849  if (!intItemQueryPart.isEmpty()) {
850  if (!queryStr.isEmpty()) {
851  queryStr += " OR ";
852  }
853  queryStr += intItemQueryPart;
854  }
855  if (!tagQueryPart.isEmpty()) {
856  if (!queryStr.isEmpty()) {
857  queryStr += " OR ";
858  }
859  queryStr += tagQueryPart;
860  }
861  return queryStr;
862  }
863 
864  @NbBundle.Messages({
865  "# {0} - filters",
866  "SearchFiltering.ScoreFilter.desc=Score(s) of : {0}",})
867  @Override
868  public String getDesc() {
869  return Bundle.SearchFiltering_ScoreFilter_desc(
870  concatenateSetNamesForDisplay(scores.stream().map(p -> p.toString()).collect(Collectors.toList())));
871  }
872  }
873 
878  public static class TagsFilter extends AbstractFilter {
879 
880  private final List<TagName> tagNames;
881 
887  public TagsFilter(List<TagName> tagNames) {
888  this.tagNames = tagNames;
889  }
890 
891  @Override
892  public String getWhereClause() {
893  String tagIDs = ""; // NON-NLS
894  for (TagName tagName : tagNames) {
895  if (!tagIDs.isEmpty()) {
896  tagIDs += ",";
897  }
898  tagIDs += tagName.getId();
899  }
900 
901  String queryStr = "(obj_id IN (SELECT obj_id FROM content_tags WHERE tag_name_id IN (" + tagIDs + ")))";
902 
903  return queryStr;
904  }
905 
906  @NbBundle.Messages({
907  "# {0} - tag names",
908  "FileSearchFiltering.TagsFilter.desc=Tagged {0}",
909  "FileSearchFiltering.TagsFilter.or=, ",})
910  @Override
911  public String getDesc() {
912  String desc = ""; // NON-NLS
913  for (TagName name : tagNames) {
914  if (!desc.isEmpty()) {
915  desc += Bundle.FileSearchFiltering_TagsFilter_or();
916  }
917  desc += name.getDisplayName();
918  }
919  return Bundle.FileSearchFiltering_TagsFilter_desc(desc);
920  }
921  }
922 
927  public static class UserCreatedFilter extends AbstractFilter {
928 
929  @Override
930  public String getWhereClause() {
931  return "(obj_id IN (SELECT obj_id from blackboard_artifacts WHERE artifact_id IN "
932  + "(SELECT artifact_id FROM blackboard_attributes WHERE artifact_type_id = "
933  + BlackboardArtifact.ARTIFACT_TYPE.TSK_USER_CONTENT_SUSPECTED.getTypeID() + ")))";
934  }
935 
936  @NbBundle.Messages({
937  "FileSearchFiltering.UserCreatedFilter.desc=that contain EXIF data",})
938  @Override
939  public String getDesc() {
940  return Bundle.FileSearchFiltering_UserCreatedFilter_desc();
941  }
942  }
943 
948  public static class NotableFilter extends AbstractFilter {
949 
950  @Override
951  public String getWhereClause() {
952  // Since this relies on the central repository database, there is no
953  // query on the case database.
954  return ""; // NON-NLS
955  }
956 
957  @Override
958  public boolean useAlternateFilter() {
959  return true;
960  }
961 
962  @Override
963  public List<Result> applyAlternateFilter(List<Result> currentResults, SleuthkitCase caseDb,
964  CentralRepository centralRepoDb) throws DiscoveryException {
965 
966  if (centralRepoDb == null) {
967  throw new DiscoveryException("Can not run Previously Notable filter with null Central Repository DB"); // NON-NLS
968  }
969 
970  // We have to have run some kind of SQL filter before getting to this point,
971  // and should have checked afterward to see if the results were empty.
972  if (currentResults.isEmpty()) {
973  throw new DiscoveryException("Can not run on empty list"); // NON-NLS
974  }
975 
976  // The matching files
977  List<Result> notableResults = new ArrayList<>();
978 
979  try {
981 
982  for (Result result : currentResults) {
983  ResultFile file = (ResultFile) result;
984  if (result.getType() == SearchData.Type.DOMAIN) {
985  break;
986  }
987  if (file.getFirstInstance().getMd5Hash() != null && !file.getFirstInstance().getMd5Hash().isEmpty()) {
988  // Check if this file hash is marked as notable in the CR
989  String value = file.getFirstInstance().getMd5Hash();
990  if (centralRepoDb.getCountArtifactInstancesKnownBad(type, value) > 0) {
991  notableResults.add(result);
992  }
993  }
994  }
995  return notableResults;
997  throw new DiscoveryException("Error querying central repository", ex); // NON-NLS
998  }
999  }
1000 
1001  @NbBundle.Messages({
1002  "FileSearchFiltering.PreviouslyNotableFilter.desc=that were previously marked as notable",})
1003  @Override
1004  public String getDesc() {
1005  return Bundle.FileSearchFiltering_PreviouslyNotableFilter_desc();
1006  }
1007  }
1008 
1012  public static class KnownFilter extends AbstractFilter {
1013 
1014  @Override
1015  public String getWhereClause() {
1016  return "known!=" + TskData.FileKnown.KNOWN.getFileKnownValue(); // NON-NLS
1017  }
1018 
1019  @NbBundle.Messages({
1020  "FileSearchFiltering.KnownFilter.desc=which are not known"})
1021  @Override
1022  public String getDesc() {
1023  return Bundle.FileSearchFiltering_KnownFilter_desc();
1024  }
1025  }
1026 
1034  @NbBundle.Messages({
1035  "FileSearchFiltering.concatenateSetNamesForDisplay.comma=, ",})
1036  private static String concatenateSetNamesForDisplay(List<String> setNames) {
1037  String desc = ""; // NON-NLS
1038  for (String setName : setNames) {
1039  if (!desc.isEmpty()) {
1040  desc += Bundle.FileSearchFiltering_concatenateSetNamesForDisplay_comma();
1041  }
1042  desc += setName;
1043  }
1044  return desc;
1045  }
1046 
1055  private static String concatenateNamesForSQL(List<String> setNames) {
1056  String result = ""; // NON-NLS
1057  for (String setName : setNames) {
1058  if (!result.isEmpty()) {
1059  result += " OR "; // NON-NLS
1060  }
1061  result += "value_text = \'" + setName + "\'"; // NON-NLS
1062  }
1063  return result;
1064  }
1065 
1069  private SearchFiltering() {
1070  // Class should not be instantiated
1071  }
1072 }
static String concatenateNamesForSQL(List< String > setNames)
ParentSearchTerm(String searchStr, boolean isFullPath, boolean isIncluded)
Long getCountArtifactInstancesKnownBad(CorrelationAttributeInstance.Type aType, String value)
static String concatenateSetNamesForDisplay(List< String > setNames)
List< Result > applyAlternateFilter(List< Result > currentResults, SleuthkitCase caseDb, CentralRepository centralRepoDb)
List< Result > applyAlternateFilter(List< Result > currentResults, SleuthkitCase caseDb, CentralRepository centralRepoDb)
static List< Result > getResultList(List< AbstractFilter > filters, String combinedQuery, SleuthkitCase caseDb, CentralRepository centralRepoDb)

Copyright © 2012-2020 Basis Technology. Generated on: Tue Sep 22 2020
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.