Autopsy  4.13.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
FileSearchFiltering.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2019 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.filequery;
20 
30 
31 import org.sleuthkit.datamodel.AbstractFile;
32 import org.sleuthkit.datamodel.DataSource;
33 import org.sleuthkit.datamodel.SleuthkitCase;
34 import org.sleuthkit.datamodel.TagName;
35 import org.sleuthkit.datamodel.TskCoreException;
36 
37 import java.util.ArrayList;
38 import java.util.List;
39 import java.util.logging.Level;
40 import java.util.stream.Collectors;
41 import org.openide.util.NbBundle;
42 import org.sleuthkit.datamodel.BlackboardArtifact;
43 import org.sleuthkit.datamodel.BlackboardAttribute;
44 import org.sleuthkit.datamodel.TskData;
45 
49 class FileSearchFiltering {
50 
51  private final static Logger logger = Logger.getLogger(FileSearchFiltering.class.getName());
52 
63  static List<ResultFile> runQueries(List<FileFilter> filters, SleuthkitCase caseDb, EamDb centralRepoDb) throws FileSearchException {
64 
65  if (caseDb == null) {
66  throw new FileSearchException("Case DB parameter is null"); // NON-NLS
67  }
68 
69  // Record the selected filters
70  String filterStr = "";
71  for (FileFilter filter : filters) {
72  filterStr += " " + filter.getDesc() + "\n";
73  }
74  logger.log(Level.INFO, "Running filters:\n{0}", filterStr);
75 
76  // Combine all the SQL queries from the filters into one query
77  String combinedQuery = "";
78  for (FileFilter filter : filters) {
79  if (!filter.getWhereClause().isEmpty()) {
80  if (!combinedQuery.isEmpty()) {
81  combinedQuery += " AND "; // NON-NLS
82  }
83  combinedQuery += "(" + filter.getWhereClause() + ")"; // NON-NLS
84  }
85  }
86 
87  if (combinedQuery.isEmpty()) {
88  // The file search filter is required, so this should never be empty.
89  throw new FileSearchException("Selected filters do not include a case database query");
90  }
91  try {
92  return getResultList(filters, combinedQuery, caseDb, centralRepoDb);
93  } catch (TskCoreException ex) {
94  throw new FileSearchException("Error querying case database", ex); // NON-NLS
95  }
96  }
97 
112  private static List<ResultFile> getResultList(List<FileFilter> filters, String combinedQuery, SleuthkitCase caseDb, EamDb centralRepoDb) throws TskCoreException, FileSearchException {
113  // Get all matching abstract files
114  List<ResultFile> resultList = new ArrayList<>();
115 
116  logger.log(Level.INFO, "Running SQL query: {0}", combinedQuery);
117  List<AbstractFile> sqlResults = caseDb.findAllFilesWhere(combinedQuery);
118 
119  // If there are no results, return now
120  if (sqlResults.isEmpty()) {
121  return resultList;
122  }
123 
124  // Wrap each result in a ResultFile
125  for (AbstractFile abstractFile : sqlResults) {
126  resultList.add(new ResultFile(abstractFile));
127  }
128 
129  // Now run any non-SQL filters.
130  for (FileFilter filter : filters) {
131  if (filter.useAlternateFilter()) {
132  resultList = filter.applyAlternateFilter(resultList, caseDb, centralRepoDb);
133  }
134  // There are no matches for the filters run so far, so return
135  if (resultList.isEmpty()) {
136  return resultList;
137  }
138  }
139  return resultList;
140  }
141 
145  static abstract class FileFilter {
146 
154  abstract String getWhereClause();
155 
162  boolean useAlternateFilter() {
163  return false;
164  }
165 
180  List<ResultFile> applyAlternateFilter(List<ResultFile> currentResults, SleuthkitCase caseDb,
181  EamDb centralRepoDb) throws FileSearchException {
182  return new ArrayList<>();
183  }
184 
190  abstract String getDesc();
191  }
192 
196  static class SizeFilter extends FileFilter {
197 
198  private final List<FileSize> fileSizes;
199 
205  SizeFilter(List<FileSize> fileSizes) {
206  this.fileSizes = fileSizes;
207  }
208 
209  @Override
210  String getWhereClause() {
211  String queryStr = ""; // NON-NLS
212  for (FileSize size : fileSizes) {
213  if (!queryStr.isEmpty()) {
214  queryStr += " OR "; // NON-NLS
215  }
216  if (size.getMaxBytes() != FileSize.NO_MAXIMUM) {
217  queryStr += "(size > \'" + size.getMinBytes() + "\' AND size <= \'" + size.getMaxBytes() + "\')"; // NON-NLS
218  } else {
219  queryStr += "(size >= \'" + size.getMinBytes() + "\')"; // NON-NLS
220  }
221  }
222  return queryStr;
223  }
224 
225  @NbBundle.Messages({
226  "# {0} - filters",
227  "FileSearchFiltering.SizeFilter.desc=Files with size in range(s): {0}",
228  "FileSearchFiltering.SizeFilter.or= or ",
229  "# {0} - Minimum bytes",
230  "# {1} - Maximum bytes",
231  "FileSearchFiltering.SizeFilter.range=({0} to {1})",})
232  @Override
233  String getDesc() {
234  String desc = ""; // NON-NLS
235  for (FileSize size : fileSizes) {
236  if (!desc.isEmpty()) {
237  desc += Bundle.FileSearchFiltering_SizeFilter_or();
238  }
239  desc += Bundle.FileSearchFiltering_SizeFilter_range(size.getMinBytes(), size.getMaxBytes());
240  }
241  desc = Bundle.FileSearchFiltering_SizeFilter_desc(desc);
242  return desc;
243  }
244  }
245 
250  static class ParentSearchTerm {
251 
252  private final String searchStr;
253  private final boolean fullPath;
254  private final boolean included;
255 
265  ParentSearchTerm(String searchStr, boolean isFullPath, boolean isIncluded) {
266  this.searchStr = searchStr;
267  this.fullPath = isFullPath;
268  this.included = isIncluded;
269  }
270 
276  String getSQLForTerm() {
277  // TODO - these should really be prepared statements
278  if (isIncluded()) {
279  if (isFullPath()) {
280  return "parent_path=\'" + getSearchStr() + "\'"; // NON-NLS
281  } else {
282  return "parent_path LIKE \'%" + getSearchStr() + "%\'"; // NON-NLS
283  }
284  } else {
285  if (isFullPath()) {
286  return "parent_path!=\'" + getSearchStr() + "\'"; // NON-NLS
287  } else {
288  return "parent_path NOT LIKE \'%" + getSearchStr() + "%\'"; // NON-NLS
289  }
290  }
291  }
292 
293  @NbBundle.Messages({
294  "FileSearchFiltering.ParentSearchTerm.fullString= (exact)",
295  "FileSearchFiltering.ParentSearchTerm.subString= (substring)",
296  "FileSearchFiltering.ParentSearchTerm.includeString= (include)",
297  "FileSearchFiltering.ParentSearchTerm.excludeString= (exclude)",})
298  @Override
299  public String toString() {
300  String returnString = getSearchStr();
301  if (isFullPath()) {
302  returnString += Bundle.FileSearchFiltering_ParentSearchTerm_fullString();
303  } else {
304  returnString += Bundle.FileSearchFiltering_ParentSearchTerm_subString();
305  }
306  if (isIncluded()) {
307  returnString += Bundle.FileSearchFiltering_ParentSearchTerm_includeString();
308  } else {
309  returnString += Bundle.FileSearchFiltering_ParentSearchTerm_excludeString();
310  }
311  return returnString;
312  }
313 
317  boolean isFullPath() {
318  return fullPath;
319  }
320 
324  boolean isIncluded() {
325  return included;
326  }
327 
331  String getSearchStr() {
332  return searchStr;
333  }
334  }
335 
339  static class ParentFilter extends FileFilter {
340 
341  private final List<ParentSearchTerm> parentSearchTerms;
342 
348  ParentFilter(List<ParentSearchTerm> parentSearchTerms) {
349  this.parentSearchTerms = parentSearchTerms;
350  }
351 
352  @Override
353  String getWhereClause() {
354  String includeQueryStr = ""; // NON-NLS
355  String excludeQueryStr = "";
356  for (ParentSearchTerm searchTerm : parentSearchTerms) {
357  if (searchTerm.isIncluded()) {
358  if (!includeQueryStr.isEmpty()) {
359  includeQueryStr += " OR "; // NON-NLS
360  }
361  includeQueryStr += searchTerm.getSQLForTerm();
362  } else {
363  if (!excludeQueryStr.isEmpty()) {
364  excludeQueryStr += " AND "; // NON-NLS
365  }
366  excludeQueryStr += searchTerm.getSQLForTerm();
367  }
368  }
369  if (!includeQueryStr.isEmpty()) {
370  includeQueryStr = "(" + includeQueryStr + ")";
371  }
372  if (!excludeQueryStr.isEmpty()) {
373  excludeQueryStr = "(" + excludeQueryStr + ")";
374  }
375  if (includeQueryStr.isEmpty() || excludeQueryStr.isEmpty()) {
376  return includeQueryStr + excludeQueryStr;
377  } else {
378  return includeQueryStr + " AND " + excludeQueryStr;
379  }
380  }
381 
382  @NbBundle.Messages({
383  "# {0} - filters",
384  "FileSearchFiltering.ParentFilter.desc=Files with paths matching: {0}",
385  "FileSearchFiltering.ParentFilter.or= or ",
386  "FileSearchFiltering.ParentFilter.exact=(exact match)",
387  "FileSearchFiltering.ParentFilter.substring=(substring)",})
388  @Override
389  String getDesc() {
390  String desc = ""; // NON-NLS
391  for (ParentSearchTerm searchTerm : parentSearchTerms) {
392  if (!desc.isEmpty()) {
393  desc += Bundle.FileSearchFiltering_ParentFilter_or();
394  }
395  if (searchTerm.isFullPath()) {
396  desc += searchTerm.getSearchStr() + Bundle.FileSearchFiltering_ParentFilter_exact();
397  } else {
398  desc += searchTerm.getSearchStr() + Bundle.FileSearchFiltering_ParentFilter_substring();
399  }
400  }
401  desc = Bundle.FileSearchFiltering_ParentFilter_desc(desc);
402  return desc;
403  }
404  }
405 
409  static class DataSourceFilter extends FileFilter {
410 
411  private final List<DataSource> dataSources;
412 
418  DataSourceFilter(List<DataSource> dataSources) {
419  this.dataSources = dataSources;
420  }
421 
422  @Override
423  String getWhereClause() {
424  String queryStr = ""; // NON-NLS
425  for (DataSource ds : dataSources) {
426  if (!queryStr.isEmpty()) {
427  queryStr += ","; // NON-NLS
428  }
429  queryStr += "\'" + ds.getId() + "\'"; // NON-NLS
430  }
431  queryStr = "data_source_obj_id IN (" + queryStr + ")"; // NON-NLS
432  return queryStr;
433  }
434 
435  @NbBundle.Messages({
436  "# {0} - filters",
437  "FileSearchFiltering.DataSourceFilter.desc=Files in data source(s): {0}",
438  "FileSearchFiltering.DataSourceFilter.or= or ",
439  "# {0} - Data source name",
440  "# {1} - Data source ID",
441  "FileSearchFiltering.DataSourceFilter.datasource={0}({1})",})
442  @Override
443  String getDesc() {
444  String desc = ""; // NON-NLS
445  for (DataSource ds : dataSources) {
446  if (!desc.isEmpty()) {
447  desc += Bundle.FileSearchFiltering_DataSourceFilter_or();
448  }
449  desc += Bundle.FileSearchFiltering_DataSourceFilter_datasource(ds.getName(), ds.getId());
450  }
451  desc = Bundle.FileSearchFiltering_DataSourceFilter_desc(desc);
452  return desc;
453  }
454  }
455 
460  static class KeywordListFilter extends FileFilter {
461 
462  private final List<String> listNames;
463 
469  KeywordListFilter(List<String> listNames) {
470  this.listNames = listNames;
471  }
472 
473  @Override
474  String getWhereClause() {
475  String keywordListPart = concatenateNamesForSQL(listNames);
476 
477  String queryStr = "(obj_id IN (SELECT obj_id from blackboard_artifacts WHERE artifact_id IN "
478  + "(SELECT artifact_id FROM blackboard_attributes WHERE artifact_type_id = 9 AND attribute_type_ID = 37 "
479  + "AND (" + keywordListPart + "))))"; // NON-NLS
480 
481  return queryStr;
482  }
483 
484  @NbBundle.Messages({
485  "# {0} - filters",
486  "FileSearchFiltering.KeywordListFilter.desc=Files with keywords in list(s): {0}",})
487  @Override
488  String getDesc() {
489  return Bundle.FileSearchFiltering_KeywordListFilter_desc(concatenateSetNamesForDisplay(listNames));
490  }
491  }
492 
496  static class FileTypeFilter extends FileFilter {
497 
498  private final List<FileType> categories;
499 
505  FileTypeFilter(List<FileType> categories) {
506  this.categories = categories;
507  }
508 
514  FileTypeFilter(FileType category) {
515  this.categories = new ArrayList<>();
516  this.categories.add(category);
517  }
518 
519  @Override
520  String getWhereClause() {
521  String queryStr = ""; // NON-NLS
522  for (FileType cat : categories) {
523  for (String type : cat.getMediaTypes()) {
524  if (!queryStr.isEmpty()) {
525  queryStr += ","; // NON-NLS
526  }
527  queryStr += "\'" + type + "\'"; // NON-NLS
528  }
529  }
530  queryStr = "mime_type IN (" + queryStr + ")"; // NON-NLS
531  return queryStr;
532  }
533 
534  @NbBundle.Messages({
535  "# {0} - filters",
536  "FileSearchFiltering.FileTypeFilter.desc=Files with type: {0}",
537  "FileSearchFiltering.FileTypeFilter.or= or ",})
538  @Override
539  String getDesc() {
540  String desc = "";
541  for (FileType cat : categories) {
542  if (!desc.isEmpty()) {
543  desc += Bundle.FileSearchFiltering_FileTypeFilter_or();
544  }
545  desc += cat.toString();
546  }
547  desc = Bundle.FileSearchFiltering_FileTypeFilter_desc(desc);
548  return desc;
549  }
550  }
551 
555  static class FrequencyFilter extends FileFilter {
556 
557  private final List<Frequency> frequencies;
558 
564  FrequencyFilter(List<Frequency> frequencies) {
565  this.frequencies = frequencies;
566  }
567 
568  @Override
569  String getWhereClause() {
570  // Since this relies on the central repository database, there is no
571  // query on the case database.
572  return ""; // NON-NLS
573  }
574 
575  @Override
576  boolean useAlternateFilter() {
577  return true;
578  }
579 
580  @Override
581  List<ResultFile> applyAlternateFilter(List<ResultFile> currentResults, SleuthkitCase caseDb,
582  EamDb centralRepoDb) throws FileSearchException {
583 
584  // We have to have run some kind of SQL filter before getting to this point,
585  // and should have checked afterward to see if the results were empty.
586  if (currentResults.isEmpty()) {
587  throw new FileSearchException("Can not run on empty list"); // NON-NLS
588  }
589 
590  // Set the frequency for each file
591  FileSearch.FrequencyAttribute freqAttr = new FileSearch.FrequencyAttribute();
592  freqAttr.addAttributeToResultFiles(currentResults, caseDb, centralRepoDb);
593 
594  // If the frequency matches the filter, add the file to the results
595  List<ResultFile> frequencyResults = new ArrayList<>();
596  for (ResultFile file : currentResults) {
597  if (frequencies.contains(file.getFrequency())) {
598  frequencyResults.add(file);
599  }
600  }
601  return frequencyResults;
602  }
603 
604  @NbBundle.Messages({
605  "# {0} - filters",
606  "FileSearchFiltering.FrequencyFilter.desc=Files with frequency: {0}",
607  "FileSearchFiltering.FrequencyFilter.or= or ",})
608  @Override
609  String getDesc() {
610  String desc = ""; // NON-NLS
611  for (Frequency freq : frequencies) {
612  if (!desc.isEmpty()) {
613  desc += Bundle.FileSearchFiltering_FrequencyFilter_or();
614  }
615  desc += freq.name();
616  }
617  return Bundle.FileSearchFiltering_FrequencyFilter_desc(desc);
618  }
619  }
620 
625  static class HashSetFilter extends FileFilter {
626 
627  private final List<String> setNames;
628 
634  HashSetFilter(List<String> setNames) {
635  this.setNames = setNames;
636  }
637 
638  @Override
639  String getWhereClause() {
640  String hashSetPart = concatenateNamesForSQL(setNames);
641 
642  String queryStr = "(obj_id IN (SELECT obj_id from blackboard_artifacts WHERE artifact_id IN "
643  + "(SELECT artifact_id FROM blackboard_attributes WHERE artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()
644  + " AND attribute_type_ID = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + " "
645  + "AND (" + hashSetPart + "))))"; // NON-NLS
646 
647  return queryStr;
648  }
649 
650  @NbBundle.Messages({
651  "# {0} - filters",
652  "FileSearchFiltering.HashSetFilter.desc=Files with hash set hits in set(s): {0}",})
653  @Override
654  String getDesc() {
655  return Bundle.FileSearchFiltering_HashSetFilter_desc(concatenateSetNamesForDisplay(setNames));
656  }
657  }
658 
663  static class InterestingFileSetFilter extends FileFilter {
664 
665  private final List<String> setNames;
666 
672  InterestingFileSetFilter(List<String> setNames) {
673  this.setNames = setNames;
674  }
675 
676  @Override
677  String getWhereClause() {
678  String intItemSetPart = concatenateNamesForSQL(setNames);
679 
680  String queryStr = "(obj_id IN (SELECT obj_id from blackboard_artifacts WHERE artifact_id IN "
681  + "(SELECT artifact_id FROM blackboard_attributes WHERE artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID()
682  + " AND attribute_type_ID = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + " "
683  + "AND (" + intItemSetPart + "))))"; // NON-NLS
684 
685  return queryStr;
686  }
687 
688  @NbBundle.Messages({
689  "# {0} - filters",
690  "FileSearchFiltering.InterestingItemSetFilter.desc=Files with interesting item hits in set(s): {0}",})
691  @Override
692  String getDesc() {
693  return Bundle.FileSearchFiltering_InterestingItemSetFilter_desc(concatenateSetNamesForDisplay(setNames));
694  }
695  }
696 
701  static class ObjectDetectionFilter extends FileFilter {
702 
703  private final List<String> typeNames;
704 
710  ObjectDetectionFilter(List<String> typeNames) {
711  this.typeNames = typeNames;
712  }
713 
714  @Override
715  String getWhereClause() {
716  String objTypePart = concatenateNamesForSQL(typeNames);
717 
718  String queryStr = "(obj_id IN (SELECT obj_id from blackboard_artifacts WHERE artifact_id IN "
719  + "(SELECT artifact_id FROM blackboard_attributes WHERE artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID()
720  + " AND attribute_type_ID = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION.getTypeID() + " "
721  + "AND (" + objTypePart + "))))"; // NON-NLS
722 
723  return queryStr;
724  }
725 
726  @NbBundle.Messages({
727  "# {0} - filters",
728  "FileSearchFiltering.ObjectDetectionFilter.desc=Files with objects detected in set(s): {0}",})
729  @Override
730  String getDesc() {
731  return Bundle.FileSearchFiltering_ObjectDetectionFilter_desc(concatenateSetNamesForDisplay(typeNames));
732  }
733  }
734 
739  static class ScoreFilter extends FileFilter {
740 
741  private final List<Score> scores;
742 
748  ScoreFilter(List<Score> scores) {
749  this.scores = scores;
750  }
751 
752  @Override
753  String getWhereClause() {
754 
755  // Current algorithm:
756  // "Notable" if the file is a match for a notable hashset or has been tagged with a notable tag.
757  // "Interesting" if the file has an interesting item match or has been tagged with a non-notable tag.
758  String hashsetQueryPart = "";
759  String tagQueryPart = "";
760  String intItemQueryPart = "";
761 
762  if (scores.contains(Score.NOTABLE)) {
763  // do hashset
764  hashsetQueryPart = " (known = " + TskData.FileKnown.BAD.getFileKnownValue() + ") ";
765  }
766 
767  if (scores.contains(Score.INTERESTING)) {
768  // Matches interesting item artifact
769  intItemQueryPart = " (obj_id IN (SELECT obj_id from blackboard_artifacts WHERE artifact_type_id = "
770  + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() + ")) ";
771  }
772 
773  if (scores.contains(Score.NOTABLE) && scores.contains(Score.INTERESTING)) {
774  // Any tag will work
775  tagQueryPart = "(obj_id IN (SELECT obj_id FROM content_tags))";
776  } else if (scores.contains(Score.NOTABLE)) {
777  // Notable tags
778  tagQueryPart = "(obj_id IN (SELECT obj_id FROM content_tags WHERE tag_name_id IN (SELECT tag_name_id FROM tag_names WHERE knownStatus = "
779  + TskData.FileKnown.BAD.getFileKnownValue() + ")))";
780  } else if (scores.contains(Score.INTERESTING)) {
781  // Non-notable tags
782  tagQueryPart = "(obj_id IN (SELECT obj_id FROM content_tags WHERE tag_name_id IN (SELECT tag_name_id FROM tag_names WHERE knownStatus != "
783  + TskData.FileKnown.BAD.getFileKnownValue() + ")))";
784  }
785 
786  String queryStr = hashsetQueryPart;
787  if (!intItemQueryPart.isEmpty()) {
788  if (!queryStr.isEmpty()) {
789  queryStr += " OR ";
790  }
791  queryStr += intItemQueryPart;
792  }
793  if (!tagQueryPart.isEmpty()) {
794  if (!queryStr.isEmpty()) {
795  queryStr += " OR ";
796  }
797  queryStr += tagQueryPart;
798  }
799  return queryStr;
800  }
801 
802  @NbBundle.Messages({
803  "# {0} - filters",
804  "FileSearchFiltering.ScoreFilter.desc=Files with score(s) of : {0}",})
805  @Override
806  String getDesc() {
807  return Bundle.FileSearchFiltering_ScoreFilter_desc(
808  concatenateSetNamesForDisplay(scores.stream().map(p -> p.toString()).collect(Collectors.toList())));
809  }
810  }
811 
816  static class TagsFilter extends FileFilter {
817 
818  private final List<TagName> tagNames;
819 
825  TagsFilter(List<TagName> tagNames) {
826  this.tagNames = tagNames;
827  }
828 
829  @Override
830  String getWhereClause() {
831  String tagIDs = ""; // NON-NLS
832  for (TagName tagName : tagNames) {
833  if (!tagIDs.isEmpty()) {
834  tagIDs += ",";
835  }
836  tagIDs += tagName.getId();
837  }
838 
839  String queryStr = "(obj_id IN (SELECT obj_id FROM content_tags WHERE tag_name_id IN (" + tagIDs + ")))";
840 
841  return queryStr;
842  }
843 
844  @NbBundle.Messages({
845  "# {0} - tag names",
846  "FileSearchFiltering.TagsFilter.desc=Files that have been tagged {0}",
847  "FileSearchFiltering.TagsFilter.or= or ",})
848  @Override
849  String getDesc() {
850  String desc = ""; // NON-NLS
851  for (TagName name : tagNames) {
852  if (!desc.isEmpty()) {
853  desc += Bundle.FileSearchFiltering_TagsFilter_or();
854  }
855  desc += name.getDisplayName();
856  }
857  return Bundle.FileSearchFiltering_TagsFilter_desc(desc);
858  }
859  }
860 
864  static class ExifFilter extends FileFilter {
865 
869  ExifFilter() {
870  // Nothing to save
871  }
872 
873  @Override
874  String getWhereClause() {
875  return "(obj_id IN (SELECT obj_id from blackboard_artifacts WHERE artifact_id IN "
876  + "(SELECT artifact_id FROM blackboard_attributes WHERE artifact_type_id = "
877  + BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID() + ")))";
878  }
879 
880  @NbBundle.Messages({
881  "FileSearchFiltering.ExifFilter.desc=Files that contain EXIF data",})
882  @Override
883  String getDesc() {
884  return Bundle.FileSearchFiltering_ExifFilter_desc();
885  }
886  }
887 
892  static class NotableFilter extends FileFilter {
893 
897  NotableFilter() {
898  // Nothing to save
899  }
900 
901  @Override
902  String getWhereClause() {
903  // Since this relies on the central repository database, there is no
904  // query on the case database.
905  return ""; // NON-NLS
906  }
907 
908  @Override
909  boolean useAlternateFilter() {
910  return true;
911  }
912 
913  @Override
914  List<ResultFile> applyAlternateFilter(List<ResultFile> currentResults, SleuthkitCase caseDb,
915  EamDb centralRepoDb) throws FileSearchException {
916 
917  if (centralRepoDb == null) {
918  throw new FileSearchException("Can not run Previously Notable filter with null Central Repository DB"); // NON-NLS
919  }
920 
921  // We have to have run some kind of SQL filter before getting to this point,
922  // and should have checked afterward to see if the results were empty.
923  if (currentResults.isEmpty()) {
924  throw new FileSearchException("Can not run on empty list"); // NON-NLS
925  }
926 
927  // The matching files
928  List<ResultFile> notableResults = new ArrayList<>();
929 
930  try {
931  CorrelationAttributeInstance.Type type = CorrelationAttributeInstance.getDefaultCorrelationTypes().get(CorrelationAttributeInstance.FILES_TYPE_ID);
932 
933  for (ResultFile file : currentResults) {
934  if (file.getFirstInstance().getMd5Hash() != null && !file.getFirstInstance().getMd5Hash().isEmpty()) {
935 
936  // Check if this file hash is marked as notable in the CR
937  String value = file.getFirstInstance().getMd5Hash();
938  if (centralRepoDb.getCountArtifactInstancesKnownBad(type, value) > 0) {
939  notableResults.add(file);
940  }
941  }
942  }
943  return notableResults;
944  } catch (EamDbException | CorrelationAttributeNormalizationException ex) {
945  throw new FileSearchException("Error querying central repository", ex); // NON-NLS
946  }
947  }
948 
949  @NbBundle.Messages({
950  "FileSearchFiltering.PreviouslyNotableFilter.desc=Files that were previously marked as notable",})
951  @Override
952  String getDesc() {
953  return Bundle.FileSearchFiltering_PreviouslyNotableFilter_desc();
954  }
955  }
956 
960  static class KnownFilter extends FileFilter {
961 
962  @Override
963  String getWhereClause() {
964  return "known!=" + TskData.FileKnown.KNOWN.getFileKnownValue(); // NON-NLS
965  }
966 
967  @NbBundle.Messages({
968  "FileSearchFiltering.KnownFilter.desc=Files which are not known"})
969  @Override
970  String getDesc() {
971  return Bundle.FileSearchFiltering_KnownFilter_desc();
972  }
973  }
974 
975  @NbBundle.Messages({
976  "FileSearchFiltering.concatenateSetNamesForDisplay.comma=, ",})
977  private static String concatenateSetNamesForDisplay(List<String> setNames) {
978  String desc = ""; // NON-NLS
979  for (String setName : setNames) {
980  if (!desc.isEmpty()) {
981  desc += Bundle.FileSearchFiltering_concatenateSetNamesForDisplay_comma();
982  }
983  desc += setName;
984  }
985  return desc;
986  }
987 
996  private static String concatenateNamesForSQL(List<String> setNames) {
997  String result = ""; // NON-NLS
998  for (String setName : setNames) {
999  if (!result.isEmpty()) {
1000  result += " OR "; // NON-NLS
1001  }
1002  result += "value_text = \'" + setName + "\'"; // NON-NLS
1003  }
1004  return result;
1005  }
1006 
1007  private FileSearchFiltering() {
1008  // Class should not be instantiated
1009  }
1010 }

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