Autopsy 4.22.1
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 */
19package org.sleuthkit.autopsy.datasourcesummary.datamodel;
20
21import java.text.DateFormat;
22import java.text.SimpleDateFormat;
23import java.time.Instant;
24import java.util.ArrayList;
25import java.util.Arrays;
26import java.util.Collections;
27import java.util.Date;
28import java.util.HashMap;
29import java.util.HashSet;
30import java.util.List;
31import java.util.Locale;
32import java.util.Map;
33import java.util.Set;
34import java.util.TimeZone;
35import org.joda.time.Interval;
36import org.sleuthkit.datamodel.DataSource;
37import org.sleuthkit.datamodel.TimelineEvent;
38import org.sleuthkit.datamodel.TimelineEventType;
39import org.sleuthkit.datamodel.TimelineFilter.RootFilter;
40import org.sleuthkit.datamodel.TimelineManager;
41import org.sleuthkit.datamodel.TskCoreException;
42import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
43import java.util.function.Supplier;
44import org.sleuthkit.autopsy.core.UserPreferences;
45
49public 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
88
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
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}
Map< Long, DailyActivityAmount > getTimelineEventsByDay(DataSource dataSource, TimelineManager timelineManager, TimeZone timeZone)
static String formatDate(Date date, DateFormat formatter)
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)

Copyright © 2012-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.