Autopsy  4.20.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
TimelineSummary.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2020-2021 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.datasourcesummary.datamodel;
20 
21 import java.text.DateFormat;
22 import java.text.SimpleDateFormat;
23 import java.time.Instant;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Collections;
27 import java.util.Date;
28 import java.util.HashMap;
29 import java.util.HashSet;
30 import java.util.List;
31 import java.util.Locale;
32 import java.util.Map;
33 import java.util.Set;
34 import java.util.TimeZone;
35 import org.joda.time.Interval;
36 import org.sleuthkit.datamodel.DataSource;
37 import org.sleuthkit.datamodel.TimelineEvent;
38 import org.sleuthkit.datamodel.TimelineEventType;
39 import org.sleuthkit.datamodel.TimelineFilter.RootFilter;
40 import org.sleuthkit.datamodel.TimelineManager;
41 import org.sleuthkit.datamodel.TskCoreException;
43 import java.util.function.Supplier;
45 
49 public class TimelineSummary {
50 
55  public interface DataSourceFilterFunction {
56 
65  RootFilter apply(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException;
66  }
67 
68  private static final long DAY_SECS = 24 * 60 * 60;
69  private static final Set<TimelineEventType> FILE_SYSTEM_EVENTS
70  = new HashSet<>(Arrays.asList(
71  TimelineEventType.FILE_MODIFIED,
72  TimelineEventType.FILE_ACCESSED,
73  TimelineEventType.FILE_CREATED,
74  TimelineEventType.FILE_CHANGED));
75 
77  private final Supplier<TimeZone> timeZoneProvider;
79 
83  public TimelineSummary() {
85  () -> TimeZone.getTimeZone(UserPreferences.getTimeZoneForDisplays()),
87  }
88 
97  public TimelineSummary(SleuthkitCaseProvider caseProvider, Supplier<TimeZone> timeZoneProvider, DataSourceFilterFunction filterFunction) {
98  this.caseProvider = caseProvider;
99  this.timeZoneProvider = timeZoneProvider;
100  this.filterFunction = filterFunction;
101  }
102 
115  public TimelineSummaryData getTimelineSummaryData(DataSource dataSource, int recentDaysNum) throws SleuthkitCaseProviderException, TskCoreException {
116  TimeZone timeZone = this.timeZoneProvider.get();
117  TimelineManager timelineManager = this.caseProvider.get().getTimelineManager();
118 
119  // get a mapping of days from epoch to the activity for that day
120  Map<Long, DailyActivityAmount> dateCounts = getTimelineEventsByDay(dataSource, timelineManager, timeZone);
121 
122  // get minimum and maximum usage date by iterating through
123  Long minDay = null;
124  Long maxDay = null;
125  for (long daysFromEpoch : dateCounts.keySet()) {
126  minDay = (minDay == null) ? daysFromEpoch : Math.min(minDay, daysFromEpoch);
127  maxDay = (maxDay == null) ? daysFromEpoch : Math.max(maxDay, daysFromEpoch);
128  }
129 
130  // if no min date or max date, no usage; return null.
131  if (minDay == null || maxDay == null) {
132  return null;
133  }
134 
135  Date minDate = new Date(minDay * 1000 * DAY_SECS);
136  Date maxDate = new Date(maxDay * 1000 * DAY_SECS);
137 
138  // The minimum recent day will be within recentDaysNum from the maximum day
139  // (+1 since maxDay included) or the minimum day of activity
140  long minRecentDay = Math.max(maxDay - recentDaysNum + 1, minDay);
141 
142  // get most recent days activity
143  List<DailyActivityAmount> mostRecentActivityAmt = getMostRecentActivityAmounts(dateCounts, minRecentDay, maxDay);
144 
145  return new TimelineSummaryData(minDate, maxDate, mostRecentActivityAmt, dataSource);
146  }
147 
159  private List<DailyActivityAmount> getMostRecentActivityAmounts(Map<Long, DailyActivityAmount> dateCounts, long minRecentDay, long maxDay) {
160  List<DailyActivityAmount> mostRecentActivityAmt = new ArrayList<>();
161 
162  for (long curRecentDay = minRecentDay; curRecentDay <= maxDay; curRecentDay++) {
163  DailyActivityAmount prevCounts = dateCounts.get(curRecentDay);
164  DailyActivityAmount countsHandleNotFound = prevCounts != null
165  ? prevCounts
166  : new DailyActivityAmount(new Date(curRecentDay * DAY_SECS * 1000), 0, 0);
167 
168  mostRecentActivityAmt.add(countsHandleNotFound);
169  }
170  return mostRecentActivityAmt;
171  }
172 
186  private Map<Long, DailyActivityAmount> getTimelineEventsByDay(DataSource dataSource, TimelineManager timelineManager, TimeZone timeZone)
187  throws TskCoreException, SleuthkitCaseProviderException {
188  RootFilter rootFilter = this.filterFunction.apply(dataSource);
189 
190  // get events for data source
191  long curRunTime = System.currentTimeMillis();
192  List<TimelineEvent> events = timelineManager.getEvents(new Interval(1, curRunTime), rootFilter);
193 
194  // get counts of events per day (left is file system events, right is everything else)
195  Map<Long, DailyActivityAmount> dateCounts = new HashMap<>();
196  for (TimelineEvent evt : events) {
197  long curSecondsFromEpoch = evt.getTime();
198  long curDaysFromEpoch = Instant.ofEpochMilli(curSecondsFromEpoch * 1000)
199  .atZone(timeZone.toZoneId())
200  .toLocalDate()
201  .toEpochDay();
202 
203  DailyActivityAmount prevAmt = dateCounts.get(curDaysFromEpoch);
204  long prevFileEvtCount = prevAmt == null ? 0 : prevAmt.getFileActivityCount();
205  long prevArtifactEvtCount = prevAmt == null ? 0 : prevAmt.getArtifactActivityCount();
206  Date thisDay = prevAmt == null ? new Date(curDaysFromEpoch * 1000 * DAY_SECS) : prevAmt.getDay();
207 
208  boolean isFileEvt = FILE_SYSTEM_EVENTS.contains(evt.getEventType());
209  long curFileEvtCount = prevFileEvtCount + (isFileEvt ? 1 : 0);
210  long curArtifactEvtCount = prevArtifactEvtCount + (isFileEvt ? 0 : 1);
211 
212  dateCounts.put(curDaysFromEpoch, new DailyActivityAmount(thisDay, curFileEvtCount, curArtifactEvtCount));
213  }
214 
215  return dateCounts;
216  }
217 
221  public static class TimelineSummaryData {
222 
223  private final Date minDate;
224  private final Date maxDate;
225  private final List<DailyActivityAmount> histogramActivity;
226  private final DataSource dataSource;
227 
240  TimelineSummaryData(Date minDate, Date maxDate, List<DailyActivityAmount> recentDaysActivity, DataSource dataSource) {
241  this.minDate = minDate;
242  this.maxDate = maxDate;
243  this.histogramActivity = (recentDaysActivity == null) ? Collections.emptyList() : Collections.unmodifiableList(recentDaysActivity);
244  this.dataSource = dataSource;
245  }
246 
250  public Date getMinDate() {
251  return minDate;
252  }
253 
257  public Date getMaxDate() {
258  return maxDate;
259  }
260 
265  public List<DailyActivityAmount> getMostRecentDaysActivity() {
266  return histogramActivity;
267  }
268 
272  public DataSource getDataSource() {
273  return dataSource;
274  }
275  }
276 
280  public static class DailyActivityAmount {
281 
282  private final Date day;
283  private final long fileActivityCount;
284  private final long artifactActivityCount;
285 
295  DailyActivityAmount(Date day, long fileActivityCount, long artifactActivityCount) {
296  this.day = day;
297  this.fileActivityCount = fileActivityCount;
298  this.artifactActivityCount = artifactActivityCount;
299  }
300 
304  public Date getDay() {
305  return day;
306  }
307 
311  public long getFileActivityCount() {
312  return fileActivityCount;
313  }
314 
318  public long getArtifactActivityCount() {
319  return artifactActivityCount;
320  }
321  }
322 
329  public static DateFormat getUtcFormat(String formatString) {
330  return new SimpleDateFormat(formatString, Locale.getDefault());
331  }
332 
343  public static String formatDate(Date date, DateFormat formatter) {
344  return date == null ? null : formatter.format(date);
345  }
346 }
TimelineSummaryData getTimelineSummaryData(DataSource dataSource, int recentDaysNum)
TimelineSummary(SleuthkitCaseProvider caseProvider, Supplier< TimeZone > timeZoneProvider, DataSourceFilterFunction filterFunction)
List< DailyActivityAmount > getMostRecentActivityAmounts(Map< Long, DailyActivityAmount > dateCounts, long minRecentDay, long maxDay)
Map< Long, DailyActivityAmount > getTimelineEventsByDay(DataSource dataSource, TimelineManager timelineManager, TimeZone timeZone)
static String formatDate(Date date, DateFormat formatter)

Copyright © 2012-2022 Basis Technology. Generated on: Tue Aug 1 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.