19 package org.sleuthkit.autopsy.timeline.db;
 
   21 import java.util.Collections;
 
   22 import java.util.List;
 
   23 import java.util.function.Function;
 
   24 import java.util.stream.Collectors;
 
   25 import java.util.stream.Stream;
 
   26 import javax.annotation.Nonnull;
 
   27 import org.apache.commons.lang3.StringUtils;
 
   62     static String useHashHitTablesHelper(RootFilter filter) {
 
   63         HashHitsFilter hashHitFilter = filter.getHashHitsFilter();
 
   64         return hashHitFilter.isActive() ? 
" LEFT JOIN hash_set_hits " : 
" "; 
 
   67     static String useTagTablesHelper(RootFilter filter) {
 
   68         TagsFilter tagsFilter = filter.getTagsFilter();
 
   69         return tagsFilter.isActive() ? 
" LEFT JOIN tags " : 
" "; 
 
   84     static <X> List<X> unGroupConcat(String groupConcat, Function<String, X> mapper) {
 
   85         return StringUtils.isBlank(groupConcat) ? Collections.emptyList()
 
   86                 : Stream.of(groupConcat.split(
","))
 
   88                 .collect(Collectors.toList());
 
  100     private static String getSQLWhere(IntersectionFilter<?> filter) {
 
  101         String join = String.join(
" and ", filter.getSubFilters().stream()
 
  103                 .map(SQLHelper::getSQLWhere)
 
  104                 .collect(Collectors.toList()));
 
  105         return "(" + StringUtils.defaultIfBlank(join, 
"1") + 
")";
 
  117     private static String getSQLWhere(UnionFilter<?> filter) {
 
  118         String join = String.join(
" or ", filter.getSubFilters().stream()
 
  120                 .map(SQLHelper::getSQLWhere)
 
  121                 .collect(Collectors.toList()));
 
  122         return "(" + StringUtils.defaultIfBlank(join, 
"1") + 
")";
 
  125     static String getSQLWhere(RootFilter filter) {
 
  126         return getSQLWhere((Filter) filter);
 
  141     private static String getSQLWhere(Filter filter) {
 
  143         if (filter == null) {
 
  145         } 
else if (filter instanceof DescriptionFilter) {
 
  146             result = getSQLWhere((DescriptionFilter) filter);
 
  147         } 
else if (filter instanceof TagsFilter) {
 
  148             result = getSQLWhere((TagsFilter) filter);
 
  149         } 
else if (filter instanceof HashHitsFilter) {
 
  150             result = getSQLWhere((HashHitsFilter) filter);
 
  151         } 
else if (filter instanceof DataSourceFilter) {
 
  152             result = getSQLWhere((DataSourceFilter) filter);
 
  153         } 
else if (filter instanceof DataSourcesFilter) {
 
  154             result = getSQLWhere((DataSourcesFilter) filter);
 
  155         } 
else if (filter instanceof HideKnownFilter) {
 
  156             result = getSQLWhere((HideKnownFilter) filter);
 
  157         } 
else if (filter instanceof HashHitsFilter) {
 
  158             result = getSQLWhere((HashHitsFilter) filter);
 
  159         } 
else if (filter instanceof TextFilter) {
 
  160             result = getSQLWhere((TextFilter) filter);
 
  161         } 
else if (filter instanceof TypeFilter) {
 
  162             result = getSQLWhere((TypeFilter) filter);
 
  163         } 
else if (filter instanceof IntersectionFilter) {
 
  164             result = getSQLWhere((IntersectionFilter) filter);
 
  165         } 
else if (filter instanceof UnionFilter) {
 
  166             result = getSQLWhere((UnionFilter) filter);
 
  168             throw new IllegalArgumentException(
"getSQLWhere not defined for " + filter.getClass().getCanonicalName());
 
  170         result = StringUtils.deleteWhitespace(result).equals(
"(1and1and1)") ? 
"1" : result; 
 
  171         result = StringUtils.deleteWhitespace(result).equals(
"()") ? 
"1" : result;
 
  175     private static String getSQLWhere(HideKnownFilter filter) {
 
  176         if (filter.isActive()) {
 
  177             return "(known_state IS NOT '" + TskData.FileKnown.KNOWN.getFileKnownValue() + 
"')"; 
 
  183     private static String getSQLWhere(DescriptionFilter filter) {
 
  184         if (filter.isActive()) {
 
  185             String likeOrNotLike = (filter.getFilterMode() == DescriptionFilter.FilterMode.INCLUDE ? 
"" : 
" NOT") + 
" LIKE '"; 
 
  186             return "(" + getDescriptionColumn(filter.getDescriptionLoD()) + likeOrNotLike + filter.getDescription() + 
"'  )"; 
 
  192     private static String getSQLWhere(TagsFilter filter) {
 
  193         if (filter.isActive()
 
  194                 && (filter.getSubFilters().isEmpty() == 
false)) {
 
  195             String tagNameIDs = filter.getSubFilters().stream()
 
  196                     .filter((TagNameFilter t) -> t.isSelected() && !t.isDisabled())
 
  197                     .map((TagNameFilter t) -> String.valueOf(t.getTagName().getId()))
 
  198                     .collect(Collectors.joining(
", ", 
"(", 
")"));
 
  199             return "(events.event_id == tags.event_id AND "  
  200                     + 
"tags.tag_name_id IN " + tagNameIDs + 
") "; 
 
  207     private static String getSQLWhere(HashHitsFilter filter) {
 
  208         if (filter.isActive()
 
  209                 && (filter.getSubFilters().isEmpty() == 
false)) {
 
  210             String hashSetIDs = filter.getSubFilters().stream()
 
  211                     .filter((HashSetFilter t) -> t.isSelected() && !t.isDisabled())
 
  212                     .map((HashSetFilter t) -> String.valueOf(t.getHashSetID()))
 
  213                     .collect(Collectors.joining(
", ", 
"(", 
")"));
 
  214             return "(hash_set_hits.hash_set_id IN " + hashSetIDs + 
" AND hash_set_hits.event_id == events.event_id)"; 
 
  220     private static String getSQLWhere(DataSourceFilter filter) {
 
  221         if (filter.isActive()) {
 
  222             return "(datasource_id = '" + filter.getDataSourceID() + 
"')"; 
 
  228     private static String getSQLWhere(DataSourcesFilter filter) {
 
  229         return (filter.isActive()) ? 
"(datasource_id in ("  
  230                 + filter.getSubFilters().stream()
 
  232                 .map((dataSourceFilter) -> String.valueOf(dataSourceFilter.getDataSourceID()))
 
  233                 .collect(Collectors.joining(
", ")) + 
"))" : 
"1";
 
  236     private static String getSQLWhere(TextFilter filter) {
 
  237         if (filter.isActive()) {
 
  238             if (StringUtils.isBlank(filter.getText())) {
 
  241             String strippedFilterText = StringUtils.strip(filter.getText());
 
  242             return "((med_description like '%" + strippedFilterText + 
"%')"  
  243                     + 
" or (full_description like '%" + strippedFilterText + 
"%')"  
  244                     + 
" or (short_description like '%" + strippedFilterText + 
"%'))"; 
 
  258     private static String getSQLWhere(TypeFilter typeFilter) {
 
  259         if (typeFilter.isSelected() == 
false) {
 
  261         } 
else if (typeFilter.getEventType() instanceof RootEventType) {
 
  262             if (typeFilter.getSubFilters().stream()
 
  263                     .allMatch(subFilter -> subFilter.isActive() && subFilter.getSubFilters().stream().allMatch(
Filter::isActive))) {
 
  267         return "(sub_type IN (" + StringUtils.join(getActiveSubTypes(typeFilter), 
",") + 
"))"; 
 
  270     private static List<Integer> getActiveSubTypes(TypeFilter filter) {
 
  271         if (filter.isActive()) {
 
  272             if (filter.getSubFilters().isEmpty()) {
 
  273                 return Collections.singletonList(RootEventType.allTypes.indexOf(filter.getEventType()));
 
  275                 return filter.getSubFilters().stream().flatMap((Filter t) -> getActiveSubTypes((TypeFilter) t).stream()).collect(Collectors.toList());
 
  278             return Collections.emptyList();
 
  294     static String getStrfTimeFormat(@Nonnull TimeUnits timeUnit) {
 
  297                 return "%Y-01-01T00:00:00"; 
 
  299                 return "%Y-%m-01T00:00:00"; 
 
  301                 return "%Y-%m-%dT00:00:00"; 
 
  303                 return "%Y-%m-%dT%H:00:00"; 
 
  305                 return "%Y-%m-%dT%H:%M:00"; 
 
  308                 return "%Y-%m-%dT%H:%M:%S"; 
 
  312     static String getDescriptionColumn(DescriptionLoD lod) {
 
  315                 return "full_description"; 
 
  317                 return "med_description"; 
 
  320                 return "short_description"; 
 
  324     private SQLHelper() {