mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-17 18:17:43 +00:00
cleanup getAggregateEvents()
This commit is contained in:
parent
6bfd5e9afc
commit
0fc4cbd753
@ -84,7 +84,7 @@ public class SaveSnapshot extends Action {
|
||||
|
||||
ZoomParams get = controller.getEventsModel().zoomParamtersProperty().get();
|
||||
reportMetaData.add(new Pair<>("Time Range", get.getTimeRange().toString())); // NON-NLS
|
||||
reportMetaData.add(new Pair<>("Description Level of Detail", get.getDescrLOD().getDisplayName())); // NON-NLS
|
||||
reportMetaData.add(new Pair<>("Description Level of Detail", get.getDescriptionLOD().getDisplayName())); // NON-NLS
|
||||
reportMetaData.add(new Pair<>("Event Type Zoom Level", get.getTypeZoomLevel().getDisplayName())); // NON-NLS
|
||||
reportMetaData.add(new Pair<>("Filters", get.getFilter().getHTMLReportString())); // NON-NLS
|
||||
|
||||
|
@ -173,14 +173,14 @@ public final class FilteredEventsModel {
|
||||
|
||||
if (zoomParams != null) {
|
||||
if (zoomParams.getTypeZoomLevel().equals(requestedTypeZoom.get()) == false
|
||||
|| zoomParams.getDescrLOD().equals(requestedLOD.get()) == false
|
||||
|| zoomParams.getDescriptionLOD().equals(requestedLOD.get()) == false
|
||||
|| zoomParams.getFilter().equals(requestedFilter.get()) == false
|
||||
|| zoomParams.getTimeRange().equals(requestedTimeRange.get()) == false) {
|
||||
|
||||
requestedTypeZoom.set(zoomParams.getTypeZoomLevel());
|
||||
requestedFilter.set(zoomParams.getFilter().copyOf());
|
||||
requestedTimeRange.set(zoomParams.getTimeRange());
|
||||
requestedLOD.set(zoomParams.getDescrLOD());
|
||||
requestedLOD.set(zoomParams.getDescriptionLOD());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -32,6 +32,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
@ -44,7 +45,6 @@ import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import javax.annotation.Nonnull;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.joda.time.DateTimeZone;
|
||||
@ -56,23 +56,15 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.timeline.TimeLineController;
|
||||
import org.sleuthkit.autopsy.timeline.events.AggregateEvent;
|
||||
import org.sleuthkit.autopsy.timeline.events.TimeLineEvent;
|
||||
import static org.sleuthkit.autopsy.timeline.events.db.SQLHelper.useHashHitTablesHelper;
|
||||
import static org.sleuthkit.autopsy.timeline.events.db.SQLHelper.useTagTablesHelper;
|
||||
import org.sleuthkit.autopsy.timeline.events.type.BaseTypes;
|
||||
import org.sleuthkit.autopsy.timeline.events.type.EventType;
|
||||
import org.sleuthkit.autopsy.timeline.events.type.RootEventType;
|
||||
import org.sleuthkit.autopsy.timeline.filters.RootFilter;
|
||||
import org.sleuthkit.autopsy.timeline.utils.RangeDivisionInfo;
|
||||
import org.sleuthkit.autopsy.timeline.zooming.DescriptionLOD;
|
||||
import static org.sleuthkit.autopsy.timeline.zooming.DescriptionLOD.FULL;
|
||||
import static org.sleuthkit.autopsy.timeline.zooming.DescriptionLOD.MEDIUM;
|
||||
import static org.sleuthkit.autopsy.timeline.zooming.DescriptionLOD.SHORT;
|
||||
import org.sleuthkit.autopsy.timeline.zooming.EventTypeZoomLevel;
|
||||
import org.sleuthkit.autopsy.timeline.zooming.TimeUnits;
|
||||
import static org.sleuthkit.autopsy.timeline.zooming.TimeUnits.DAYS;
|
||||
import static org.sleuthkit.autopsy.timeline.zooming.TimeUnits.HOURS;
|
||||
import static org.sleuthkit.autopsy.timeline.zooming.TimeUnits.MINUTES;
|
||||
import static org.sleuthkit.autopsy.timeline.zooming.TimeUnits.MONTHS;
|
||||
import static org.sleuthkit.autopsy.timeline.zooming.TimeUnits.SECONDS;
|
||||
import static org.sleuthkit.autopsy.timeline.zooming.TimeUnits.YEARS;
|
||||
import org.sleuthkit.autopsy.timeline.zooming.ZoomParams;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
@ -868,9 +860,9 @@ public class EventDB {
|
||||
final boolean useSubTypes = (zoomLevel == EventTypeZoomLevel.SUB_TYPE);
|
||||
|
||||
//get some info about the range of dates requested
|
||||
final String queryString = "select count(*), " + useSubTypeHelper(useSubTypes)
|
||||
final String queryString = "select count(*), " + typeColumnHelper(useSubTypes)
|
||||
+ " from events" + useHashHitTablesHelper(filter) + " where time >= " + startTime + " and time < " + endTime + " and " + SQLHelper.getSQLWhere(filter) // NON-NLS
|
||||
+ " GROUP BY " + useSubTypeHelper(useSubTypes); // NON-NLS
|
||||
+ " GROUP BY " + typeColumnHelper(useSubTypes); // NON-NLS
|
||||
|
||||
DBLock.lock();
|
||||
try (Statement stmt = con.createStatement();
|
||||
@ -891,119 +883,140 @@ public class EventDB {
|
||||
return typeMap;
|
||||
}
|
||||
|
||||
List<AggregateEvent> getAggregatedEvents(ZoomParams params) {
|
||||
return getAggregatedEvents(params.getTimeRange(), params.getFilter(), params.getTypeZoomLevel(), params.getDescrLOD());
|
||||
}
|
||||
|
||||
/**
|
||||
* //TODO: update javadoc //TODO: split this into helper methods
|
||||
*
|
||||
* get a list of {@link AggregateEvent}s.
|
||||
*
|
||||
* General algorithm is as follows:
|
||||
*
|
||||
* 1)get all aggregate events, via one db query. 2) sort them into a map
|
||||
* from (type, description)-> aggevent 3) for each key in map, merge the
|
||||
* events and accumulate them in a list to return
|
||||
*
|
||||
*
|
||||
* @param timeRange the Interval within in which all returned aggregate
|
||||
* events will be.
|
||||
* @param filter only events that pass the filter will be included in
|
||||
* aggregates events returned
|
||||
* @param zoomLevel only events of this level will be included
|
||||
* @param lod description level of detail to use when grouping events
|
||||
* get a list of {@link AggregateEvent}s, clustered according to the given
|
||||
* zoom paramaters.
|
||||
*
|
||||
* @param params the zoom params that determine the zooming, filtering and
|
||||
* clustering.
|
||||
*
|
||||
* @return a list of aggregate events within the given timerange, that pass
|
||||
* the supplied filter, aggregated according to the given event type
|
||||
* and description zoom levels
|
||||
*/
|
||||
private List<AggregateEvent> getAggregatedEvents(Interval timeRange, RootFilter filter, EventTypeZoomLevel zoomLevel, DescriptionLOD lod) {
|
||||
String descriptionColumn = getDescriptionColumn(lod);
|
||||
final boolean useSubTypes = (zoomLevel.equals(EventTypeZoomLevel.SUB_TYPE));
|
||||
List<AggregateEvent> getAggregatedEvents(ZoomParams params) {
|
||||
//unpack params
|
||||
Interval timeRange = params.getTimeRange();
|
||||
RootFilter filter = params.getFilter();
|
||||
DescriptionLOD descriptionLOD = params.getDescriptionLOD();
|
||||
EventTypeZoomLevel typeZoomLevel = params.getTypeZoomLevel();
|
||||
|
||||
//get some info about the time range requested
|
||||
RangeDivisionInfo rangeInfo = RangeDivisionInfo.getRangeDivisionInfo(timeRange);
|
||||
//use 'rounded out' range
|
||||
long start = timeRange.getStartMillis() / 1000;//.getLowerBound();
|
||||
long end = timeRange.getEndMillis() / 1000;//Millis();//rangeInfo.getUpperBound();
|
||||
if (Objects.equals(start, end)) {
|
||||
//ensure length of querried interval is not 0
|
||||
long start = timeRange.getStartMillis() / 1000;
|
||||
long end = timeRange.getEndMillis() / 1000;
|
||||
if (start == end) {
|
||||
end++;
|
||||
}
|
||||
//get some info about the time range requested
|
||||
RangeDivisionInfo rangeInfo = RangeDivisionInfo.getRangeDivisionInfo(timeRange);
|
||||
|
||||
//get a sqlite srtftime format string
|
||||
String strfTimeFormat = getStrfTimeFormat(rangeInfo.getPeriodSize());
|
||||
//build dynamic parts of query
|
||||
String strfTimeFormat = SQLHelper.getStrfTimeFormat(rangeInfo);
|
||||
String descriptionColumn = SQLHelper.getDescriptionColumn(descriptionLOD);
|
||||
final boolean useSubTypes = typeZoomLevel.equals(EventTypeZoomLevel.SUB_TYPE);
|
||||
String timeZone = TimeLineController.getTimeZone().get().equals(TimeZone.getDefault()) ? ", 'localtime'" : ""; // NON-NLS
|
||||
String typeColumn = typeColumnHelper(useSubTypes);
|
||||
|
||||
//effectively map from type to (map from description to events)
|
||||
Map<EventType, SetMultimap< String, AggregateEvent>> typeMap = new HashMap<>();
|
||||
//compose query string
|
||||
String query = "SELECT strftime('" + strfTimeFormat + "',time , 'unixepoch'" + timeZone + ") AS interval," // NON-NLS
|
||||
+ " group_concat(events.event_id) as event_ids, min(time), max(time), " + typeColumn + ", " + descriptionColumn // NON-NLS
|
||||
+ "\n FROM events" + useHashHitTablesHelper(filter) + useTagTablesHelper(filter) // NON-NLS
|
||||
+ "\n WHERE time >= " + start + " AND time < " + end + " AND " + SQLHelper.getSQLWhere(filter) // NON-NLS
|
||||
+ "\n GROUP BY interval, " + typeColumn + " , " + descriptionColumn // NON-NLS
|
||||
+ "\n ORDER BY min(time)"; // NON-NLS
|
||||
|
||||
//get all agregate events in this time unit
|
||||
// perform query and map results to AggregateEvent objects
|
||||
List<AggregateEvent> events = new ArrayList<>();
|
||||
DBLock.lock();
|
||||
String query = "select strftime('" + strfTimeFormat + "',time , 'unixepoch'" + (TimeLineController.getTimeZone().get().equals(TimeZone.getDefault()) ? ", 'localtime'" : "") + ") as interval,"
|
||||
+ " group_concat(events.event_id) as event_ids, Min(time), Max(time), " + descriptionColumn + ", " + useSubTypeHelper(useSubTypes)
|
||||
+ " from events" + useHashHitTablesHelper(filter) + useTagTablesHelper(filter) + " where " + "time >= " + start + " and time < " + end + " and " + SQLHelper.getSQLWhere(filter) // NON-NLS
|
||||
+ " group by interval, " + useSubTypeHelper(useSubTypes) + " , " + descriptionColumn // NON-NLS
|
||||
+ " order by Min(time)"; // NON-NLS
|
||||
// scoop up requested events in groups organized by interval, type, and desription
|
||||
try (ResultSet rs = con.createStatement().executeQuery(query);) {
|
||||
|
||||
try (Statement createStatement = con.createStatement();
|
||||
ResultSet rs = createStatement.executeQuery(query)) {
|
||||
while (rs.next()) {
|
||||
Interval interval = new Interval(rs.getLong("Min(time)") * 1000, rs.getLong("Max(time)") * 1000, TimeLineController.getJodaTimeZone());
|
||||
String eventIDS = rs.getString("event_ids");
|
||||
EventType type = useSubTypes ? RootEventType.allTypes.get(rs.getInt("sub_type")) : BaseTypes.values()[rs.getInt("base_type")];
|
||||
|
||||
HashSet<Long> hashHits = new HashSet<>();
|
||||
HashSet<Long> tagged = new HashSet<>();
|
||||
try (Statement st2 = con.createStatement();
|
||||
ResultSet eventHashHitOrTagged = st2.executeQuery("select event_id , tagged, hash_hit from events where event_id in (" + eventIDS + ")");) {
|
||||
while (eventHashHitOrTagged.next()) {
|
||||
long eventID = eventHashHitOrTagged.getLong("event_id");
|
||||
if (eventHashHitOrTagged.getInt("tagged") != 0) {
|
||||
tagged.add(eventID);
|
||||
}
|
||||
if (eventHashHitOrTagged.getInt("hash_hit") != 0) {
|
||||
hashHits.add(eventID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AggregateEvent aggregateEvent = new AggregateEvent(
|
||||
interval,
|
||||
type,
|
||||
Stream.of(eventIDS.split(",")).map(Long::valueOf).collect(Collectors.toSet()), // NON-NLS
|
||||
hashHits,
|
||||
tagged,
|
||||
rs.getString(descriptionColumn),
|
||||
lod);
|
||||
|
||||
//put events in map from type/descrition -> event
|
||||
SetMultimap<String, AggregateEvent> descrMap = typeMap.get(type);
|
||||
if (descrMap == null) {
|
||||
descrMap = HashMultimap.<String, AggregateEvent>create();
|
||||
typeMap.put(type, descrMap);
|
||||
}
|
||||
descrMap.put(aggregateEvent.getDescription(), aggregateEvent);
|
||||
events.add(aggregateEventHelper(rs, useSubTypes, descriptionLOD));
|
||||
}
|
||||
|
||||
} catch (SQLException ex) {
|
||||
Exceptions.printStackTrace(ex);
|
||||
LOGGER.log(Level.SEVERE, "Failed to get aggregate events with query: " + query, ex); // NON-NLS
|
||||
} finally {
|
||||
DBLock.unlock();
|
||||
}
|
||||
|
||||
return mergeAggregateEvents(rangeInfo.getPeriodSize().getPeriod(), events);
|
||||
}
|
||||
|
||||
/**
|
||||
* map a single row in a ResultSet to an AggregateEvent
|
||||
*
|
||||
* @param rs the result set whose current row should be mapped
|
||||
* @param useSubTypes use the sub_type column if true, else use the
|
||||
* base_type column
|
||||
* @param descriptionLOD the description level of detail for this event
|
||||
*
|
||||
* @return an AggregateEvent corresponding to the current row in the given
|
||||
* result set
|
||||
*
|
||||
* @throws SQLException
|
||||
*/
|
||||
private AggregateEvent aggregateEventHelper(ResultSet rs, boolean useSubTypes, DescriptionLOD descriptionLOD) throws SQLException {
|
||||
Interval interval = new Interval(rs.getLong("min(time)") * 1000, rs.getLong("max(time)") * 1000, TimeLineController.getJodaTimeZone());// NON-NLS
|
||||
String eventIDsString = rs.getString("event_ids");// NON-NLS
|
||||
Set<Long> eventIDs = SQLHelper.unGroupConcat(eventIDsString, Long::valueOf);
|
||||
String description = rs.getString(SQLHelper.getDescriptionColumn(descriptionLOD));
|
||||
EventType type = useSubTypes ? RootEventType.allTypes.get(rs.getInt("sub_type")) : BaseTypes.values()[rs.getInt("base_type")];// NON-NLS
|
||||
|
||||
Set<Long> hashHits = new HashSet<>();
|
||||
String hashHitQuery = "SELECT group_concat(event_id) FROM events WHERE event_id IN (" + eventIDsString + ") AND hash_hit = 1";// NON-NLS
|
||||
try (Statement stmt = con.createStatement();
|
||||
ResultSet hashHitsRS = stmt.executeQuery(hashHitQuery)) {
|
||||
while (hashHitsRS.next()) {
|
||||
hashHits = SQLHelper.unGroupConcat(hashHitsRS.getString("group_concat(event_id)"), Long::valueOf);// NON-NLS
|
||||
}
|
||||
}
|
||||
|
||||
Set<Long> tagged = new HashSet<>();
|
||||
String taggedQuery = "SELECT group_concat(event_id) FROM events WHERE event_id IN (" + eventIDsString + ") AND tagged = 1";// NON-NLS
|
||||
try (Statement stmt = con.createStatement();
|
||||
ResultSet taggedRS = stmt.executeQuery(taggedQuery)) {
|
||||
while (taggedRS.next()) {
|
||||
tagged = SQLHelper.unGroupConcat(taggedRS.getString("group_concat(event_id)"), Long::valueOf);// NON-NLS
|
||||
}
|
||||
}
|
||||
|
||||
return new AggregateEvent(interval, type, eventIDs, hashHits, tagged,
|
||||
description, descriptionLOD);
|
||||
}
|
||||
|
||||
/**
|
||||
* merge the events in the given list if they are within the same period
|
||||
* General algorithm is as follows:
|
||||
*
|
||||
* 1) sort them into a map from (type, description)-> List<aggevent>
|
||||
* 2) for each key in map, merge the events and accumulate them in a list to
|
||||
* return
|
||||
*
|
||||
* @param timeUnitLength
|
||||
* @param preMergedEvents
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static private List<AggregateEvent> mergeAggregateEvents(Period timeUnitLength, List<AggregateEvent> preMergedEvents) {
|
||||
|
||||
//effectively map from type to (map from description to events)
|
||||
Map<EventType, SetMultimap< String, AggregateEvent>> typeMap = new HashMap<>();
|
||||
|
||||
for (AggregateEvent aggregateEvent : preMergedEvents) {
|
||||
typeMap.computeIfAbsent(aggregateEvent.getType(), eventType -> HashMultimap.create())
|
||||
.put(aggregateEvent.getDescription(), aggregateEvent);
|
||||
}
|
||||
//result list to return
|
||||
ArrayList<AggregateEvent> aggEvents = new ArrayList<>();
|
||||
|
||||
//save this for use when comparing gap size
|
||||
Period timeUnitLength = rangeInfo.getPeriodSize().getPeriod();
|
||||
|
||||
//For each (type, description) key, merge agg events
|
||||
for (SetMultimap<String, AggregateEvent> descrMap : typeMap.values()) {
|
||||
//for each description ...
|
||||
for (String descr : descrMap.keySet()) {
|
||||
//run through the sorted events, merging together adjacent events
|
||||
Iterator<AggregateEvent> iterator = descrMap.get(descr).stream()
|
||||
.sorted((AggregateEvent o1, AggregateEvent o2)
|
||||
-> Long.compare(o1.getSpan().getStartMillis(), o2.getSpan().getStartMillis()))
|
||||
.sorted(Comparator.comparing(event -> event.getSpan().getStartMillis()))
|
||||
.iterator();
|
||||
AggregateEvent current = iterator.next();
|
||||
while (iterator.hasNext()) {
|
||||
@ -1024,21 +1037,10 @@ public class EventDB {
|
||||
aggEvents.add(current);
|
||||
}
|
||||
}
|
||||
|
||||
//at this point we should have a list of aggregate events.
|
||||
//one per type/description spanning consecutive time units as determined in rangeInfo
|
||||
return aggEvents;
|
||||
}
|
||||
|
||||
private String useHashHitTablesHelper(RootFilter filter) {
|
||||
return SQLHelper.hasActiveHashFilter(filter) ? ", hash_set_hits" : "";
|
||||
}
|
||||
|
||||
private String useTagTablesHelper(RootFilter filter) {
|
||||
return SQLHelper.hasActiveTagFilter(filter) ? ", content_tags, blackboard_artifact_tags " : "";
|
||||
}
|
||||
|
||||
private static String useSubTypeHelper(final boolean useSubTypes) {
|
||||
private static String typeColumnHelper(final boolean useSubTypes) {
|
||||
return useSubTypes ? "sub_type" : "base_type";
|
||||
}
|
||||
|
||||
@ -1065,37 +1067,6 @@ public class EventDB {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
private String getDescriptionColumn(DescriptionLOD lod) {
|
||||
switch (lod) {
|
||||
case FULL:
|
||||
return "full_description";
|
||||
case MEDIUM:
|
||||
return "med_description";
|
||||
case SHORT:
|
||||
default:
|
||||
return "short_description";
|
||||
}
|
||||
}
|
||||
|
||||
private String getStrfTimeFormat(TimeUnits info) {
|
||||
switch (info) {
|
||||
case DAYS:
|
||||
return "%Y-%m-%dT00:00:00"; // NON-NLS
|
||||
case HOURS:
|
||||
return "%Y-%m-%dT%H:00:00"; // NON-NLS
|
||||
case MINUTES:
|
||||
return "%Y-%m-%dT%H:%M:00"; // NON-NLS
|
||||
case MONTHS:
|
||||
return "%Y-%m-01T00:00:00"; // NON-NLS
|
||||
case SECONDS:
|
||||
return "%Y-%m-%dT%H:%M:%S"; // NON-NLS
|
||||
case YEARS:
|
||||
return "%Y-01-01T00:00:00"; // NON-NLS
|
||||
default:
|
||||
return "%Y-%m-%dT%H:%M:%S"; // NON-NLS
|
||||
}
|
||||
}
|
||||
|
||||
private PreparedStatement prepareStatement(String queryString) throws SQLException {
|
||||
PreparedStatement prepareStatement = con.prepareStatement(queryString);
|
||||
preparedStatements.add(prepareStatement);
|
||||
|
@ -1,13 +1,30 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013-15 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.timeline.events.db;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import javax.annotation.Nonnull;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.sleuthkit.autopsy.timeline.events.type.RootEventType;
|
||||
import org.sleuthkit.autopsy.timeline.filters.AbstractFilter;
|
||||
@ -24,47 +41,58 @@ import org.sleuthkit.autopsy.timeline.filters.TagsFilter;
|
||||
import org.sleuthkit.autopsy.timeline.filters.TextFilter;
|
||||
import org.sleuthkit.autopsy.timeline.filters.TypeFilter;
|
||||
import org.sleuthkit.autopsy.timeline.filters.UnionFilter;
|
||||
import org.sleuthkit.autopsy.timeline.utils.RangeDivisionInfo;
|
||||
import org.sleuthkit.autopsy.timeline.zooming.DescriptionLOD;
|
||||
import static org.sleuthkit.autopsy.timeline.zooming.DescriptionLOD.FULL;
|
||||
import static org.sleuthkit.autopsy.timeline.zooming.DescriptionLOD.MEDIUM;
|
||||
import static org.sleuthkit.autopsy.timeline.zooming.TimeUnits.DAYS;
|
||||
import static org.sleuthkit.autopsy.timeline.zooming.TimeUnits.HOURS;
|
||||
import static org.sleuthkit.autopsy.timeline.zooming.TimeUnits.MINUTES;
|
||||
import static org.sleuthkit.autopsy.timeline.zooming.TimeUnits.MONTHS;
|
||||
import static org.sleuthkit.autopsy.timeline.zooming.TimeUnits.SECONDS;
|
||||
import static org.sleuthkit.autopsy.timeline.zooming.TimeUnits.YEARS;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
/**
|
||||
*
|
||||
* Static helper methods for converting between java data model objects and
|
||||
* sqlite queries.
|
||||
*/
|
||||
public class SQLHelper {
|
||||
|
||||
private static List<Integer> getActiveSubTypes(TypeFilter filter) {
|
||||
if (filter.isSelected()) {
|
||||
if (filter.getSubFilters().isEmpty()) {
|
||||
return Collections.singletonList(RootEventType.allTypes.indexOf(filter.getEventType()));
|
||||
} else {
|
||||
return filter.getSubFilters().stream().flatMap((Filter t) -> getActiveSubTypes((TypeFilter) t).stream()).collect(Collectors.toList());
|
||||
}
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
static boolean hasActiveHashFilter(RootFilter filter) {
|
||||
static String useHashHitTablesHelper(RootFilter filter) {
|
||||
HashHitsFilter hashHitFilter = filter.getHashHitsFilter();
|
||||
return hashHitFilter.isSelected() && false == hashHitFilter.isDisabled();
|
||||
return hashHitFilter.isSelected() && false == hashHitFilter.isDisabled() ? ", hash_set_hits" : "";
|
||||
}
|
||||
|
||||
static boolean hasActiveTagFilter(RootFilter filter) {
|
||||
static String useTagTablesHelper(RootFilter filter) {
|
||||
TagsFilter tagsFilter = filter.getTagsFilter();
|
||||
return tagsFilter.isSelected() && false == tagsFilter.isDisabled();
|
||||
return tagsFilter.isSelected() && false == tagsFilter.isDisabled() ? ", content_tags, blackboard_artifact_tags " : "";
|
||||
}
|
||||
|
||||
private SQLHelper() {
|
||||
static <X> Set<X> unGroupConcat(String s, Function<String, X> mapper) {
|
||||
return Stream.of(s.split(","))
|
||||
.map(mapper::apply)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
static String getSQLWhere(IntersectionFilter<?> filter) {
|
||||
return filter.getSubFilters().stream().filter(Filter::isSelected).map(SQLHelper::getSQLWhere).collect(Collectors.joining(" and ", "( ", ")"));
|
||||
private static String getSQLWhere(IntersectionFilter<?> filter) {
|
||||
return filter.getSubFilters().stream()
|
||||
.filter(Filter::isSelected)
|
||||
.map(SQLHelper::getSQLWhere)
|
||||
.collect(Collectors.joining(" and ", "( ", ")"));
|
||||
}
|
||||
|
||||
static String getSQLWhere(UnionFilter<?> filter) {
|
||||
return filter.getSubFilters().stream().filter(Filter::isSelected).map(SQLHelper::getSQLWhere).collect(Collectors.joining(" or ", "( ", ")"));
|
||||
private static String getSQLWhere(UnionFilter<?> filter) {
|
||||
return filter.getSubFilters().stream()
|
||||
.filter(Filter::isSelected).map(SQLHelper::getSQLWhere)
|
||||
.collect(Collectors.joining(" or ", "( ", ")"));
|
||||
}
|
||||
|
||||
static String getSQLWhere(Filter filter) {
|
||||
static String getSQLWhere(RootFilter filter) {
|
||||
return getSQLWhere((IntersectionFilter) filter);
|
||||
}
|
||||
|
||||
private static String getSQLWhere(Filter filter) {
|
||||
String result = "";
|
||||
if (filter == null) {
|
||||
return "1";
|
||||
@ -96,7 +124,7 @@ public class SQLHelper {
|
||||
return result;
|
||||
}
|
||||
|
||||
static String getSQLWhere(HideKnownFilter filter) {
|
||||
private static String getSQLWhere(HideKnownFilter filter) {
|
||||
if (filter.isSelected()) {
|
||||
return "(known_state IS NOT '" + TskData.FileKnown.KNOWN.getFileKnownValue() + "')"; // NON-NLS
|
||||
} else {
|
||||
@ -104,7 +132,7 @@ public class SQLHelper {
|
||||
}
|
||||
}
|
||||
|
||||
static String getSQLWhere(TagsFilter filter) {
|
||||
private static String getSQLWhere(TagsFilter filter) {
|
||||
if (filter.isSelected()
|
||||
&& (false == filter.isDisabled())
|
||||
&& (filter.getSubFilters().isEmpty() == false)) {
|
||||
@ -114,13 +142,12 @@ public class SQLHelper {
|
||||
.collect(Collectors.joining(", ", "(", ")"));
|
||||
return "((blackboard_artifact_tags.artifact_id == events.artifact_id AND blackboard_artifact_tags.tag_name_id IN " + tagNameIDs + ") "
|
||||
+ "OR ( content_tags.obj_id == events.file_id AND content_tags.tag_name_id IN " + tagNameIDs + "))";
|
||||
|
||||
} else {
|
||||
return "1";
|
||||
}
|
||||
}
|
||||
|
||||
static String getSQLWhere(HashHitsFilter filter) {
|
||||
private static String getSQLWhere(HashHitsFilter filter) {
|
||||
if (filter.isSelected()
|
||||
&& (false == filter.isDisabled())
|
||||
&& (filter.getSubFilters().isEmpty() == false)) {
|
||||
@ -134,11 +161,11 @@ public class SQLHelper {
|
||||
}
|
||||
}
|
||||
|
||||
static String getSQLWhere(DataSourceFilter filter) {
|
||||
private static String getSQLWhere(DataSourceFilter filter) {
|
||||
return (filter.isSelected()) ? "(datasource_id = '" + filter.getDataSourceID() + "')" : "1";
|
||||
}
|
||||
|
||||
static String getSQLWhere(DataSourcesFilter filter) {
|
||||
private static String getSQLWhere(DataSourcesFilter filter) {
|
||||
return (filter.isSelected()) ? "(datasource_id in ("
|
||||
+ filter.getSubFilters().stream()
|
||||
.filter(AbstractFilter::isSelected)
|
||||
@ -146,7 +173,7 @@ public class SQLHelper {
|
||||
.collect(Collectors.joining(", ")) + "))" : "1";
|
||||
}
|
||||
|
||||
static String getSQLWhere(TextFilter filter) {
|
||||
private static String getSQLWhere(TextFilter filter) {
|
||||
if (filter.isSelected()) {
|
||||
if (StringUtils.isBlank(filter.getText())) {
|
||||
return "1";
|
||||
@ -168,7 +195,7 @@ public class SQLHelper {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static String getSQLWhere(TypeFilter typeFilter) {
|
||||
private static String getSQLWhere(TypeFilter typeFilter) {
|
||||
if (typeFilter.isSelected() == false) {
|
||||
return "0";
|
||||
} else if (typeFilter.getEventType() instanceof RootEventType) {
|
||||
@ -180,4 +207,59 @@ public class SQLHelper {
|
||||
return "(sub_type IN (" + StringUtils.join(getActiveSubTypes(typeFilter), ",") + "))";
|
||||
}
|
||||
|
||||
private static List<Integer> getActiveSubTypes(TypeFilter filter) {
|
||||
if (filter.isSelected()) {
|
||||
if (filter.getSubFilters().isEmpty()) {
|
||||
return Collections.singletonList(RootEventType.allTypes.indexOf(filter.getEventType()));
|
||||
} else {
|
||||
return filter.getSubFilters().stream().flatMap((Filter t) -> getActiveSubTypes((TypeFilter) t).stream()).collect(Collectors.toList());
|
||||
}
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get a sqlite strftime format string that will allow us to group by the
|
||||
* requested period size. That is, with all info more granular that that
|
||||
* requested dropped (replaced with zeros).
|
||||
*
|
||||
* @param info the {@link RangeDivisionInfo} with the requested period size
|
||||
*
|
||||
* @return a String formatted according to the sqlite strftime spec
|
||||
*
|
||||
* @see https://www.sqlite.org/lang_datefunc.html
|
||||
*/
|
||||
static String getStrfTimeFormat(@Nonnull RangeDivisionInfo info) {
|
||||
switch (info.getPeriodSize()) {
|
||||
case YEARS:
|
||||
return "%Y-01-01T00:00:00"; // NON-NLS
|
||||
case MONTHS:
|
||||
return "%Y-%m-01T00:00:00"; // NON-NLS
|
||||
case DAYS:
|
||||
return "%Y-%m-%dT00:00:00"; // NON-NLS
|
||||
case HOURS:
|
||||
return "%Y-%m-%dT%H:00:00"; // NON-NLS
|
||||
case MINUTES:
|
||||
return "%Y-%m-%dT%H:%M:00"; // NON-NLS
|
||||
case SECONDS:
|
||||
default: //seconds - should never happen
|
||||
return "%Y-%m-%dT%H:%M:%S"; // NON-NLS
|
||||
}
|
||||
}
|
||||
|
||||
static String getDescriptionColumn(DescriptionLOD lod) {
|
||||
switch (lod) {
|
||||
case FULL:
|
||||
return "full_description";
|
||||
case MEDIUM:
|
||||
return "med_description";
|
||||
case SHORT:
|
||||
default:
|
||||
return "short_description";
|
||||
}
|
||||
}
|
||||
|
||||
private SQLHelper() {
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ public class ZoomParams {
|
||||
return filter;
|
||||
}
|
||||
|
||||
public DescriptionLOD getDescrLOD() {
|
||||
public DescriptionLOD getDescriptionLOD() {
|
||||
return descrLOD;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user