Autopsy  4.15.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-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;
20 
28 import org.sleuthkit.datamodel.AbstractFile;
29 import org.sleuthkit.datamodel.DataSource;
30 import org.sleuthkit.datamodel.SleuthkitCase;
31 import org.sleuthkit.datamodel.TagName;
32 import org.sleuthkit.datamodel.TskCoreException;
33 import java.util.ArrayList;
34 import java.util.List;
35 import java.util.stream.Collectors;
36 import org.openide.util.NbBundle;
37 import org.sleuthkit.datamodel.BlackboardArtifact;
38 import org.sleuthkit.datamodel.BlackboardAttribute;
39 import org.sleuthkit.datamodel.TskData;
41 
45 class FileSearchFiltering {
46 
57  static List<ResultFile> runQueries(List<FileFilter> filters, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws FileSearchException {
58  if (caseDb == null) {
59  throw new FileSearchException("Case DB parameter is null"); // NON-NLS
60  }
61  // Combine all the SQL queries from the filters into one query
62  String combinedQuery = "";
63  for (FileFilter filter : filters) {
64  if (!filter.getWhereClause().isEmpty()) {
65  if (!combinedQuery.isEmpty()) {
66  combinedQuery += " AND "; // NON-NLS
67  }
68  combinedQuery += "(" + filter.getWhereClause() + ")"; // NON-NLS
69  }
70  }
71 
72  if (combinedQuery.isEmpty()) {
73  // The file search filter is required, so this should never be empty.
74  throw new FileSearchException("Selected filters do not include a case database query");
75  }
76  try {
77  return getResultList(filters, combinedQuery, caseDb, centralRepoDb);
78  } catch (TskCoreException ex) {
79  throw new FileSearchException("Error querying case database", ex); // NON-NLS
80  }
81  }
82 
97  private static List<ResultFile> getResultList(List<FileFilter> filters, String combinedQuery, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws TskCoreException, FileSearchException {
98  // Get all matching abstract files
99  List<ResultFile> resultList = new ArrayList<>();
100  List<AbstractFile> sqlResults = caseDb.findAllFilesWhere(combinedQuery);
101 
102  // If there are no results, return now
103  if (sqlResults.isEmpty()) {
104  return resultList;
105  }
106 
107  // Wrap each result in a ResultFile
108  for (AbstractFile abstractFile : sqlResults) {
109  resultList.add(new ResultFile(abstractFile));
110  }
111 
112  // Now run any non-SQL filters.
113  for (FileFilter filter : filters) {
114  if (filter.useAlternateFilter()) {
115  resultList = filter.applyAlternateFilter(resultList, caseDb, centralRepoDb);
116  }
117  // There are no matches for the filters run so far, so return
118  if (resultList.isEmpty()) {
119  return resultList;
120  }
121  }
122  return resultList;
123  }
124 
128  static abstract class FileFilter {
129 
137  abstract String getWhereClause();
138 
145  boolean useAlternateFilter() {
146  return false;
147  }
148 
163  List<ResultFile> applyAlternateFilter(List<ResultFile> currentResults, SleuthkitCase caseDb,
164  CentralRepository centralRepoDb) throws FileSearchException {
165  return new ArrayList<>();
166  }
167 
173  abstract String getDesc();
174  }
175 
179  static class SizeFilter extends FileFilter {
180 
181  private final List<FileSize> fileSizes;
182 
188  SizeFilter(List<FileSize> fileSizes) {
189  this.fileSizes = fileSizes;
190  }
191 
192  @Override
193  String getWhereClause() {
194  String queryStr = ""; // NON-NLS
195  for (FileSize size : fileSizes) {
196  if (!queryStr.isEmpty()) {
197  queryStr += " OR "; // NON-NLS
198  }
199  if (size.getMaxBytes() != FileSize.NO_MAXIMUM) {
200  queryStr += "(size > \'" + size.getMinBytes() + "\' AND size <= \'" + size.getMaxBytes() + "\')"; // NON-NLS
201  } else {
202  queryStr += "(size >= \'" + size.getMinBytes() + "\')"; // NON-NLS
203  }
204  }
205  return queryStr;
206  }
207 
208  @NbBundle.Messages({
209  "# {0} - filters",
210  "FileSearchFiltering.SizeFilter.desc=Size(s): {0}",
211  "FileSearchFiltering.SizeFilter.or=, "})
212  @Override
213  String getDesc() {
214  String desc = ""; // NON-NLS
215  for (FileSize size : fileSizes) {
216  if (!desc.isEmpty()) {
217  desc += Bundle.FileSearchFiltering_SizeFilter_or();
218  }
219  desc += size.getSizeGroup();
220  }
221  desc = Bundle.FileSearchFiltering_SizeFilter_desc(desc);
222  return desc;
223  }
224  }
225 
230  static class ParentSearchTerm {
231 
232  private final String searchStr;
233  private final boolean fullPath;
234  private final boolean included;
235 
245  ParentSearchTerm(String searchStr, boolean isFullPath, boolean isIncluded) {
246  this.searchStr = searchStr;
247  this.fullPath = isFullPath;
248  this.included = isIncluded;
249  }
250 
256  String getSQLForTerm() {
257  // TODO - these should really be prepared statements
258  if (isIncluded()) {
259  if (isFullPath()) {
260  return "parent_path=\'" + getSearchStr() + "\'"; // NON-NLS
261  } else {
262  return "parent_path LIKE \'%" + getSearchStr() + "%\'"; // NON-NLS
263  }
264  } else {
265  if (isFullPath()) {
266  return "parent_path!=\'" + getSearchStr() + "\'"; // NON-NLS
267  } else {
268  return "parent_path NOT LIKE \'%" + getSearchStr() + "%\'"; // NON-NLS
269  }
270  }
271  }
272 
273  @NbBundle.Messages({
274  "FileSearchFiltering.ParentSearchTerm.fullString= (exact)",
275  "FileSearchFiltering.ParentSearchTerm.subString= (substring)",
276  "FileSearchFiltering.ParentSearchTerm.includeString= (include)",
277  "FileSearchFiltering.ParentSearchTerm.excludeString= (exclude)",})
278  @Override
279  public String toString() {
280  String returnString = getSearchStr();
281  if (isFullPath()) {
282  returnString += Bundle.FileSearchFiltering_ParentSearchTerm_fullString();
283  } else {
284  returnString += Bundle.FileSearchFiltering_ParentSearchTerm_subString();
285  }
286  if (isIncluded()) {
287  returnString += Bundle.FileSearchFiltering_ParentSearchTerm_includeString();
288  } else {
289  returnString += Bundle.FileSearchFiltering_ParentSearchTerm_excludeString();
290  }
291  return returnString;
292  }
293 
297  boolean isFullPath() {
298  return fullPath;
299  }
300 
304  boolean isIncluded() {
305  return included;
306  }
307 
311  String getSearchStr() {
312  return searchStr;
313  }
314  }
315 
319  static class ParentFilter extends FileFilter {
320 
321  private final List<ParentSearchTerm> parentSearchTerms;
322 
328  ParentFilter(List<ParentSearchTerm> parentSearchTerms) {
329  this.parentSearchTerms = parentSearchTerms;
330  }
331 
332  @Override
333  String getWhereClause() {
334  String includeQueryStr = ""; // NON-NLS
335  String excludeQueryStr = "";
336  for (ParentSearchTerm searchTerm : parentSearchTerms) {
337  if (searchTerm.isIncluded()) {
338  if (!includeQueryStr.isEmpty()) {
339  includeQueryStr += " OR "; // NON-NLS
340  }
341  includeQueryStr += searchTerm.getSQLForTerm();
342  } else {
343  if (!excludeQueryStr.isEmpty()) {
344  excludeQueryStr += " AND "; // NON-NLS
345  }
346  excludeQueryStr += searchTerm.getSQLForTerm();
347  }
348  }
349  if (!includeQueryStr.isEmpty()) {
350  includeQueryStr = "(" + includeQueryStr + ")";
351  }
352  if (!excludeQueryStr.isEmpty()) {
353  excludeQueryStr = "(" + excludeQueryStr + ")";
354  }
355  if (includeQueryStr.isEmpty() || excludeQueryStr.isEmpty()) {
356  return includeQueryStr + excludeQueryStr;
357  } else {
358  return includeQueryStr + " AND " + excludeQueryStr;
359  }
360  }
361 
362  @NbBundle.Messages({
363  "# {0} - filters",
364  "FileSearchFiltering.ParentFilter.desc=Paths matching: {0}",
365  "FileSearchFiltering.ParentFilter.or=, ",
366  "FileSearchFiltering.ParentFilter.exact=(exact match)",
367  "FileSearchFiltering.ParentFilter.substring=(substring)",
368  "FileSearchFiltering.ParentFilter.included=(included)",
369  "FileSearchFiltering.ParentFilter.excluded=(excluded)"})
370  @Override
371  String getDesc() {
372  String desc = ""; // NON-NLS
373  for (ParentSearchTerm searchTerm : parentSearchTerms) {
374  if (!desc.isEmpty()) {
375  desc += Bundle.FileSearchFiltering_ParentFilter_or();
376  }
377  if (searchTerm.isFullPath()) {
378  desc += searchTerm.getSearchStr() + Bundle.FileSearchFiltering_ParentFilter_exact();
379  } else {
380  desc += searchTerm.getSearchStr() + Bundle.FileSearchFiltering_ParentFilter_substring();
381  }
382  if (searchTerm.isIncluded()) {
383  desc += Bundle.FileSearchFiltering_ParentFilter_included();
384  } else {
385  desc += Bundle.FileSearchFiltering_ParentFilter_excluded();
386  }
387  }
388  desc = Bundle.FileSearchFiltering_ParentFilter_desc(desc);
389  return desc;
390  }
391  }
392 
396  static class DataSourceFilter extends FileFilter {
397 
398  private final List<DataSource> dataSources;
399 
405  DataSourceFilter(List<DataSource> dataSources) {
406  this.dataSources = dataSources;
407  }
408 
409  @Override
410  String getWhereClause() {
411  String queryStr = ""; // NON-NLS
412  for (DataSource ds : dataSources) {
413  if (!queryStr.isEmpty()) {
414  queryStr += ","; // NON-NLS
415  }
416  queryStr += "\'" + ds.getId() + "\'"; // NON-NLS
417  }
418  queryStr = "data_source_obj_id IN (" + queryStr + ")"; // NON-NLS
419  return queryStr;
420  }
421 
422  @NbBundle.Messages({
423  "# {0} - filters",
424  "FileSearchFiltering.DataSourceFilter.desc=Data source(s): {0}",
425  "FileSearchFiltering.DataSourceFilter.or=, ",
426  "# {0} - Data source name",
427  "# {1} - Data source ID",
428  "FileSearchFiltering.DataSourceFilter.datasource={0}({1})",})
429  @Override
430  String getDesc() {
431  String desc = ""; // NON-NLS
432  for (DataSource ds : dataSources) {
433  if (!desc.isEmpty()) {
434  desc += Bundle.FileSearchFiltering_DataSourceFilter_or();
435  }
436  desc += Bundle.FileSearchFiltering_DataSourceFilter_datasource(ds.getName(), ds.getId());
437  }
438  desc = Bundle.FileSearchFiltering_DataSourceFilter_desc(desc);
439  return desc;
440  }
441  }
442 
447  static class KeywordListFilter extends FileFilter {
448 
449  private final List<String> listNames;
450 
456  KeywordListFilter(List<String> listNames) {
457  this.listNames = listNames;
458  }
459 
460  @Override
461  String getWhereClause() {
462  String keywordListPart = concatenateNamesForSQL(listNames);
463 
464  String queryStr = "(obj_id IN (SELECT obj_id from blackboard_artifacts WHERE artifact_id IN "
465  + "(SELECT artifact_id FROM blackboard_attributes WHERE artifact_type_id = 9 AND attribute_type_ID = 37 "
466  + "AND (" + keywordListPart + "))))"; // NON-NLS
467 
468  return queryStr;
469  }
470 
471  @NbBundle.Messages({
472  "# {0} - filters",
473  "FileSearchFiltering.KeywordListFilter.desc=Keywords in list(s): {0}",})
474  @Override
475  String getDesc() {
476  return Bundle.FileSearchFiltering_KeywordListFilter_desc(concatenateSetNamesForDisplay(listNames));
477  }
478  }
479 
483  static class FileTypeFilter extends FileFilter {
484 
485  private final List<FileType> categories;
486 
492  FileTypeFilter(List<FileType> categories) {
493  this.categories = categories;
494  }
495 
501  FileTypeFilter(FileType category) {
502  this.categories = new ArrayList<>();
503  this.categories.add(category);
504  }
505 
506  @Override
507  String getWhereClause() {
508  String queryStr = ""; // NON-NLS
509  for (FileType cat : categories) {
510  for (String type : cat.getMediaTypes()) {
511  if (!queryStr.isEmpty()) {
512  queryStr += ","; // NON-NLS
513  }
514  queryStr += "\'" + type + "\'"; // NON-NLS
515  }
516  }
517  queryStr = "mime_type IN (" + queryStr + ")"; // NON-NLS
518  return queryStr;
519  }
520 
521  @NbBundle.Messages({
522  "# {0} - filters",
523  "FileSearchFiltering.FileTypeFilter.desc=Type: {0}",
524  "FileSearchFiltering.FileTypeFilter.or=, ",})
525  @Override
526  String getDesc() {
527  String desc = "";
528  for (FileType cat : categories) {
529  if (!desc.isEmpty()) {
530  desc += Bundle.FileSearchFiltering_FileTypeFilter_or();
531  }
532  desc += cat.toString();
533  }
534  desc = Bundle.FileSearchFiltering_FileTypeFilter_desc(desc);
535  return desc;
536  }
537  }
538 
542  static class FrequencyFilter extends FileFilter {
543 
544  private final List<Frequency> frequencies;
545 
551  FrequencyFilter(List<Frequency> frequencies) {
552  this.frequencies = frequencies;
553  }
554 
555  @Override
556  String getWhereClause() {
557  // Since this relies on the central repository database, there is no
558  // query on the case database.
559  return ""; // NON-NLS
560  }
561 
562  @Override
563  boolean useAlternateFilter() {
564  return true;
565  }
566 
567  @Override
568  List<ResultFile> applyAlternateFilter(List<ResultFile> currentResults, SleuthkitCase caseDb,
569  CentralRepository centralRepoDb) throws FileSearchException {
570 
571  // We have to have run some kind of SQL filter before getting to this point,
572  // and should have checked afterward to see if the results were empty.
573  if (currentResults.isEmpty()) {
574  throw new FileSearchException("Can not run on empty list"); // NON-NLS
575  }
576 
577  // Set the frequency for each file
578  FileSearch.FrequencyAttribute freqAttr = new FileSearch.FrequencyAttribute();
579  freqAttr.addAttributeToResultFiles(currentResults, caseDb, centralRepoDb);
580 
581  // If the frequency matches the filter, add the file to the results
582  List<ResultFile> frequencyResults = new ArrayList<>();
583  for (ResultFile file : currentResults) {
584  if (frequencies.contains(file.getFrequency())) {
585  frequencyResults.add(file);
586  }
587  }
588  return frequencyResults;
589  }
590 
591  @NbBundle.Messages({
592  "# {0} - filters",
593  "FileSearchFiltering.FrequencyFilter.desc=Past occurrences: {0}",
594  "FileSearchFiltering.FrequencyFilter.or=, ",})
595  @Override
596  String getDesc() {
597  String desc = ""; // NON-NLS
598  for (Frequency freq : frequencies) {
599  if (!desc.isEmpty()) {
600  desc += Bundle.FileSearchFiltering_FrequencyFilter_or();
601  }
602  desc += freq.toString();
603  }
604  return Bundle.FileSearchFiltering_FrequencyFilter_desc(desc);
605  }
606  }
607 
612  static class HashSetFilter extends FileFilter {
613 
614  private final List<String> setNames;
615 
621  HashSetFilter(List<String> setNames) {
622  this.setNames = setNames;
623  }
624 
625  @Override
626  String getWhereClause() {
627  String hashSetPart = concatenateNamesForSQL(setNames);
628 
629  String queryStr = "(obj_id IN (SELECT obj_id from blackboard_artifacts WHERE artifact_id IN "
630  + "(SELECT artifact_id FROM blackboard_attributes WHERE artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()
631  + " AND attribute_type_ID = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + " "
632  + "AND (" + hashSetPart + "))))"; // NON-NLS
633 
634  return queryStr;
635  }
636 
637  @NbBundle.Messages({
638  "# {0} - filters",
639  "FileSearchFiltering.HashSetFilter.desc=Hash set hits in set(s): {0}",})
640  @Override
641  String getDesc() {
642  return Bundle.FileSearchFiltering_HashSetFilter_desc(concatenateSetNamesForDisplay(setNames));
643  }
644  }
645 
650  static class InterestingFileSetFilter extends FileFilter {
651 
652  private final List<String> setNames;
653 
659  InterestingFileSetFilter(List<String> setNames) {
660  this.setNames = setNames;
661  }
662 
663  @Override
664  String getWhereClause() {
665  String intItemSetPart = concatenateNamesForSQL(setNames);
666 
667  String queryStr = "(obj_id IN (SELECT obj_id from blackboard_artifacts WHERE artifact_id IN "
668  + "(SELECT artifact_id FROM blackboard_attributes WHERE artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID()
669  + " AND attribute_type_ID = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + " "
670  + "AND (" + intItemSetPart + "))))"; // NON-NLS
671 
672  return queryStr;
673  }
674 
675  @NbBundle.Messages({
676  "# {0} - filters",
677  "FileSearchFiltering.InterestingItemSetFilter.desc=Interesting item hits in set(s): {0}",})
678  @Override
679  String getDesc() {
680  return Bundle.FileSearchFiltering_InterestingItemSetFilter_desc(concatenateSetNamesForDisplay(setNames));
681  }
682  }
683 
688  static class ObjectDetectionFilter extends FileFilter {
689 
690  private final List<String> typeNames;
691 
697  ObjectDetectionFilter(List<String> typeNames) {
698  this.typeNames = typeNames;
699  }
700 
701  @Override
702  String getWhereClause() {
703  String objTypePart = concatenateNamesForSQL(typeNames);
704 
705  String queryStr = "(obj_id IN (SELECT obj_id from blackboard_artifacts WHERE artifact_id IN "
706  + "(SELECT artifact_id FROM blackboard_attributes WHERE artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID()
707  + " AND attribute_type_ID = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION.getTypeID() + " "
708  + "AND (" + objTypePart + "))))"; // NON-NLS
709 
710  return queryStr;
711  }
712 
713  @NbBundle.Messages({
714  "# {0} - filters",
715  "FileSearchFiltering.ObjectDetectionFilter.desc=Objects detected in set(s): {0}",})
716  @Override
717  String getDesc() {
718  return Bundle.FileSearchFiltering_ObjectDetectionFilter_desc(concatenateSetNamesForDisplay(typeNames));
719  }
720  }
721 
726  static class ScoreFilter extends FileFilter {
727 
728  private final List<Score> scores;
729 
735  ScoreFilter(List<Score> scores) {
736  this.scores = scores;
737  }
738 
739  @Override
740  String getWhereClause() {
741 
742  // Current algorithm:
743  // "Notable" if the file is a match for a notable hashset or has been tagged with a notable tag.
744  // "Interesting" if the file has an interesting item match or has been tagged with a non-notable tag.
745  String hashsetQueryPart = "";
746  String tagQueryPart = "";
747  String intItemQueryPart = "";
748 
749  if (scores.contains(Score.NOTABLE)) {
750  // do hashset
751  hashsetQueryPart = " (known = " + TskData.FileKnown.BAD.getFileKnownValue() + ") ";
752  }
753 
754  if (scores.contains(Score.INTERESTING)) {
755  // Matches interesting item artifact
756  intItemQueryPart = " (obj_id IN (SELECT obj_id from blackboard_artifacts WHERE artifact_type_id = "
757  + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() + ")) ";
758  }
759 
760  if (scores.contains(Score.NOTABLE) && scores.contains(Score.INTERESTING)) {
761  // Any tag will work
762  tagQueryPart = "(obj_id IN (SELECT obj_id FROM content_tags))";
763  } else if (scores.contains(Score.NOTABLE)) {
764  // Notable tags
765  tagQueryPart = "(obj_id IN (SELECT obj_id FROM content_tags WHERE tag_name_id IN (SELECT tag_name_id FROM tag_names WHERE knownStatus = "
766  + TskData.FileKnown.BAD.getFileKnownValue() + ")))";
767  } else if (scores.contains(Score.INTERESTING)) {
768  // Non-notable tags
769  tagQueryPart = "(obj_id IN (SELECT obj_id FROM content_tags WHERE tag_name_id IN (SELECT tag_name_id FROM tag_names WHERE knownStatus != "
770  + TskData.FileKnown.BAD.getFileKnownValue() + ")))";
771  }
772 
773  String queryStr = hashsetQueryPart;
774  if (!intItemQueryPart.isEmpty()) {
775  if (!queryStr.isEmpty()) {
776  queryStr += " OR ";
777  }
778  queryStr += intItemQueryPart;
779  }
780  if (!tagQueryPart.isEmpty()) {
781  if (!queryStr.isEmpty()) {
782  queryStr += " OR ";
783  }
784  queryStr += tagQueryPart;
785  }
786  return queryStr;
787  }
788 
789  @NbBundle.Messages({
790  "# {0} - filters",
791  "FileSearchFiltering.ScoreFilter.desc=Score(s) of : {0}",})
792  @Override
793  String getDesc() {
794  return Bundle.FileSearchFiltering_ScoreFilter_desc(
795  concatenateSetNamesForDisplay(scores.stream().map(p -> p.toString()).collect(Collectors.toList())));
796  }
797  }
798 
803  static class TagsFilter extends FileFilter {
804 
805  private final List<TagName> tagNames;
806 
812  TagsFilter(List<TagName> tagNames) {
813  this.tagNames = tagNames;
814  }
815 
816  @Override
817  String getWhereClause() {
818  String tagIDs = ""; // NON-NLS
819  for (TagName tagName : tagNames) {
820  if (!tagIDs.isEmpty()) {
821  tagIDs += ",";
822  }
823  tagIDs += tagName.getId();
824  }
825 
826  String queryStr = "(obj_id IN (SELECT obj_id FROM content_tags WHERE tag_name_id IN (" + tagIDs + ")))";
827 
828  return queryStr;
829  }
830 
831  @NbBundle.Messages({
832  "# {0} - tag names",
833  "FileSearchFiltering.TagsFilter.desc=Tagged {0}",
834  "FileSearchFiltering.TagsFilter.or=, ",})
835  @Override
836  String getDesc() {
837  String desc = ""; // NON-NLS
838  for (TagName name : tagNames) {
839  if (!desc.isEmpty()) {
840  desc += Bundle.FileSearchFiltering_TagsFilter_or();
841  }
842  desc += name.getDisplayName();
843  }
844  return Bundle.FileSearchFiltering_TagsFilter_desc(desc);
845  }
846  }
847 
852  static class UserCreatedFilter extends FileFilter {
853 
857  UserCreatedFilter() {
858  // Nothing to save
859  }
860 
861  @Override
862  String getWhereClause() {
863  return "(obj_id IN (SELECT obj_id from blackboard_artifacts WHERE artifact_id IN "
864  + "(SELECT artifact_id FROM blackboard_attributes WHERE artifact_type_id = "
865  + BlackboardArtifact.ARTIFACT_TYPE.TSK_USER_CONTENT_SUSPECTED.getTypeID() + ")))";
866  }
867 
868  @NbBundle.Messages({
869  "FileSearchFiltering.UserCreatedFilter.desc=that contain EXIF data",})
870  @Override
871  String getDesc() {
872  return Bundle.FileSearchFiltering_UserCreatedFilter_desc();
873  }
874  }
875 
880  static class NotableFilter extends FileFilter {
881 
885  NotableFilter() {
886  // Nothing to save
887  }
888 
889  @Override
890  String getWhereClause() {
891  // Since this relies on the central repository database, there is no
892  // query on the case database.
893  return ""; // NON-NLS
894  }
895 
896  @Override
897  boolean useAlternateFilter() {
898  return true;
899  }
900 
901  @Override
902  List<ResultFile> applyAlternateFilter(List<ResultFile> currentResults, SleuthkitCase caseDb,
903  CentralRepository centralRepoDb) throws FileSearchException {
904 
905  if (centralRepoDb == null) {
906  throw new FileSearchException("Can not run Previously Notable filter with null Central Repository DB"); // NON-NLS
907  }
908 
909  // We have to have run some kind of SQL filter before getting to this point,
910  // and should have checked afterward to see if the results were empty.
911  if (currentResults.isEmpty()) {
912  throw new FileSearchException("Can not run on empty list"); // NON-NLS
913  }
914 
915  // The matching files
916  List<ResultFile> notableResults = new ArrayList<>();
917 
918  try {
919  CorrelationAttributeInstance.Type type = CorrelationAttributeInstance.getDefaultCorrelationTypes().get(CorrelationAttributeInstance.FILES_TYPE_ID);
920 
921  for (ResultFile file : currentResults) {
922  if (file.getFirstInstance().getMd5Hash() != null && !file.getFirstInstance().getMd5Hash().isEmpty()) {
923 
924  // Check if this file hash is marked as notable in the CR
925  String value = file.getFirstInstance().getMd5Hash();
926  if (centralRepoDb.getCountArtifactInstancesKnownBad(type, value) > 0) {
927  notableResults.add(file);
928  }
929  }
930  }
931  return notableResults;
932  } catch (CentralRepoException | CorrelationAttributeNormalizationException ex) {
933  throw new FileSearchException("Error querying central repository", ex); // NON-NLS
934  }
935  }
936 
937  @NbBundle.Messages({
938  "FileSearchFiltering.PreviouslyNotableFilter.desc=that were previously marked as notable",})
939  @Override
940  String getDesc() {
941  return Bundle.FileSearchFiltering_PreviouslyNotableFilter_desc();
942  }
943  }
944 
948  static class KnownFilter extends FileFilter {
949 
950  @Override
951  String getWhereClause() {
952  return "known!=" + TskData.FileKnown.KNOWN.getFileKnownValue(); // NON-NLS
953  }
954 
955  @NbBundle.Messages({
956  "FileSearchFiltering.KnownFilter.desc=which are not known"})
957  @Override
958  String getDesc() {
959  return Bundle.FileSearchFiltering_KnownFilter_desc();
960  }
961  }
962 
963  @NbBundle.Messages({
964  "FileSearchFiltering.concatenateSetNamesForDisplay.comma=, ",})
965  private static String concatenateSetNamesForDisplay(List<String> setNames) {
966  String desc = ""; // NON-NLS
967  for (String setName : setNames) {
968  if (!desc.isEmpty()) {
969  desc += Bundle.FileSearchFiltering_concatenateSetNamesForDisplay_comma();
970  }
971  desc += setName;
972  }
973  return desc;
974  }
975 
984  private static String concatenateNamesForSQL(List<String> setNames) {
985  String result = ""; // NON-NLS
986  for (String setName : setNames) {
987  if (!result.isEmpty()) {
988  result += " OR "; // NON-NLS
989  }
990  result += "value_text = \'" + setName + "\'"; // NON-NLS
991  }
992  return result;
993  }
994 
995  private FileSearchFiltering() {
996  // Class should not be instantiated
997  }
998 }

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