Autopsy 4.22.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
RecentFilesSummary.java
Go to the documentation of this file.
1/*
2 * Autopsy Forensic Browser
3 *
4 * Copyright 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.nio.file.Paths;
22import java.text.DateFormat;
23import java.text.SimpleDateFormat;
24import java.util.ArrayList;
25import java.util.Collections;
26import java.util.List;
27import java.util.Locale;
28import java.util.Map;
29import java.util.Objects;
30import java.util.stream.Collectors;
31import org.apache.commons.lang.StringUtils;
32import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
33import org.sleuthkit.datamodel.AbstractFile;
34import org.sleuthkit.datamodel.BlackboardArtifact;
35import org.sleuthkit.datamodel.BlackboardAttribute;
36import org.sleuthkit.datamodel.Content;
37import org.sleuthkit.datamodel.DataSource;
38import org.sleuthkit.datamodel.SleuthkitCase;
39import org.sleuthkit.datamodel.TskCoreException;
40import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
41
45public class RecentFilesSummary {
46
47 private final static BlackboardAttribute.Type DATETIME_ACCESSED_ATT = new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED);
48 private final static BlackboardAttribute.Type DOMAIN_ATT = new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN);
49 private final static BlackboardAttribute.Type PATH_ATT = new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH);
50 private final static BlackboardAttribute.Type ASSOCATED_ATT = new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT);
51 private final static BlackboardAttribute.Type EMAIL_FROM_ATT = new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_FROM);
52 private final static BlackboardAttribute.Type MSG_DATEIME_SENT_ATT = new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT);
53 private final static BlackboardArtifact.Type ASSOCATED_OBJ_ART = new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT);
54
55 private static final DateFormat DATETIME_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.getDefault());
56
58
65
72 if (provider == null) {
73 throw new IllegalArgumentException("Unable to construct RecentFileSummary object. SleuthkitCaseProvider cannot be null");
74 }
75
76 this.provider = provider;
77 }
78
87 private static <T extends RecentFileDetails> List<T> getSortedLimited(List<T> fileDetails, int limit) {
88 Map<String, T> fileDetailsMap = fileDetails.stream()
89 .filter(details -> details != null)
90 .collect(Collectors.toMap(
91 d -> d.getPath().toUpperCase(),
92 d -> d,
93 (d1, d2) -> Long.compare(d1.getDateAsLong(), d2.getDateAsLong()) > 0 ? d1 : d2));
94
95 return fileDetailsMap.values().stream()
96 .sorted((a, b) -> -Long.compare(a.getDateAsLong(), b.getDateAsLong()))
97 .limit(limit)
98 .collect(Collectors.toList());
99 }
100
108 private static RecentFileDetails getRecentlyOpenedDocument(BlackboardArtifact artifact) {
109 String path = DataSourceInfoUtilities.getStringOrNull(artifact, PATH_ATT);
111
112 if (StringUtils.isBlank(path) || lastOpened == null || lastOpened == 0) {
113 return null;
114 } else {
115 return new RecentFileDetails(artifact, path, lastOpened);
116 }
117 }
118
133 public List<RecentFileDetails> getRecentlyOpenedDocuments(DataSource dataSource, int maxCount) throws SleuthkitCaseProviderException, TskCoreException {
134 if (dataSource == null) {
135 return Collections.emptyList();
136 }
137
138 throwOnNonPositiveCount(maxCount);
139
140 List<RecentFileDetails> details = provider.get().getBlackboard()
141 .getArtifacts(ARTIFACT_TYPE.TSK_RECENT_OBJECT.getTypeID(), dataSource.getId()).stream()
142 .map(art -> getRecentlyOpenedDocument(art))
143 .filter(d -> d != null)
144 .collect(Collectors.toList());
145
146 return getSortedLimited(details, maxCount);
147 }
148
156 private static RecentDownloadDetails getRecentDownload(BlackboardArtifact artifact) {
157 Long accessedTime = DataSourceInfoUtilities.getLongOrNull(artifact, DATETIME_ACCESSED_ATT);
158 String domain = DataSourceInfoUtilities.getStringOrNull(artifact, DOMAIN_ATT);
159 String path = DataSourceInfoUtilities.getStringOrNull(artifact, PATH_ATT);
160
161 if (StringUtils.isBlank(path) || accessedTime == null || accessedTime == 0) {
162 return null;
163 } else {
164 return new RecentDownloadDetails(artifact, path, accessedTime, domain);
165 }
166 }
167
173 private static void throwOnNonPositiveCount(int count) {
174 if (count < 1) {
175 throw new IllegalArgumentException("Invalid count: value must be greater than 0.");
176 }
177 }
178
193 public List<RecentDownloadDetails> getRecentDownloads(DataSource dataSource, int maxCount) throws TskCoreException, SleuthkitCaseProviderException {
194 if (dataSource == null) {
195 return Collections.emptyList();
196 }
197
198 throwOnNonPositiveCount(maxCount);
199
200 List<RecentDownloadDetails> details = provider.get().getBlackboard()
201 .getArtifacts(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID(), dataSource.getId()).stream()
202 .map(art -> getRecentDownload(art))
203 .filter(d -> d != null)
204 .collect(Collectors.toList());
205
206 return getSortedLimited(details, maxCount);
207 }
208
221 public List<RecentAttachmentDetails> getRecentAttachments(DataSource dataSource, int maxCount) throws SleuthkitCaseProviderException, TskCoreException {
222 if (dataSource == null) {
223 return Collections.emptyList();
224 }
225
226 throwOnNonPositiveCount(maxCount);
227
228 SleuthkitCase skCase = provider.get();
229
230 List<BlackboardArtifact> associatedArtifacts = skCase.getBlackboard()
231 .getArtifacts(ASSOCATED_OBJ_ART.getTypeID(), dataSource.getId());
232
233 List<RecentAttachmentDetails> details = new ArrayList<>();
234 for (BlackboardArtifact artifact : associatedArtifacts) {
235 RecentAttachmentDetails thisDetails = getRecentAttachment(artifact, skCase);
236
237 if (thisDetails != null) {
238 details.add(thisDetails);
239 }
240 }
241
242 return getSortedLimited(details, maxCount);
243 }
244
254 private static RecentAttachmentDetails getRecentAttachment(BlackboardArtifact artifact, SleuthkitCase skCase) throws TskCoreException {
255 // get associated artifact or return no result
256 BlackboardAttribute attribute = artifact.getAttribute(ASSOCATED_ATT);
257 if (attribute == null) {
258 return null;
259 }
260
261 // get associated message artifact if exists or return no result
262 BlackboardArtifact messageArtifact = skCase.getBlackboardArtifact(attribute.getValueLong());
263 if (messageArtifact == null || !isMessageArtifact(messageArtifact)) {
264 return null;
265 }
266
267 // get abstract file if exists or return no result
268 Content content = artifact.getParent();
269 if (!(content instanceof AbstractFile)) {
270 return null;
271 }
272
273 AbstractFile abstractFile = (AbstractFile) content;
274
275 // get the path, sender, and date
276 String path = Paths.get(abstractFile.getParentPath(), abstractFile.getName()).toString();
277 String sender = DataSourceInfoUtilities.getStringOrNull(messageArtifact, EMAIL_FROM_ATT);
278 Long date = DataSourceInfoUtilities.getLongOrNull(messageArtifact, MSG_DATEIME_SENT_ATT);
279
280 if (date == null || date == 0 || StringUtils.isBlank(path)) {
281 return null;
282 } else {
283 return new RecentAttachmentDetails(messageArtifact, path, date, sender);
284 }
285 }
286
295 private static boolean isMessageArtifact(BlackboardArtifact nodeArtifact) {
296 final int artifactTypeID = nodeArtifact.getArtifactTypeID();
297 return artifactTypeID == ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()
298 || artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID();
299
300 }
301
305 public static class RecentFileDetails {
306
307 private final String path;
308 private final long date;
309 private final BlackboardArtifact artifact;
310
318 RecentFileDetails(BlackboardArtifact artifact, String path, long date) {
319 this.artifact = artifact;
320 this.path = path;
321 this.date = date;
322 }
323
330 public String getDateAsString() {
331 return DATETIME_FORMAT.format(date * 1000);
332 }
333
339 public Long getDateAsLong() {
340 return date;
341 }
342
348 public String getPath() {
349 return path;
350 }
351
355 public BlackboardArtifact getArtifact() {
356 return artifact;
357 }
358 }
359
363 public static class RecentDownloadDetails extends RecentFileDetails {
364
365 private final String webDomain;
366
375 RecentDownloadDetails(BlackboardArtifact artifact, String path, long date, String webDomain) {
376 super(artifact, path, date);
377 this.webDomain = webDomain;
378 }
379
386 public String getWebDomain() {
387 return webDomain;
388 }
389 }
390
394 public static class RecentAttachmentDetails extends RecentFileDetails {
395
396 private final String sender;
397
408 RecentAttachmentDetails(BlackboardArtifact artifact, String path, long date, String sender) {
409 super(artifact, path, date);
410 this.sender = sender;
411 }
412
419 public String getSender() {
420 return sender;
421 }
422
423 @Override
424 public boolean equals(Object obj) {
425 if (!(obj instanceof RecentAttachmentDetails)) {
426 return false;
427 }
428 RecentAttachmentDetails compareObj = (RecentAttachmentDetails) obj;
429
430 return compareObj.getSender().equals(this.sender)
431 && compareObj.getPath().equals(this.getPath())
432 && compareObj.getDateAsLong().equals(this.getDateAsLong());
433 }
434
435 @Override
436 public int hashCode() {
437 int hash = 5;
438 hash = 73 * hash + Objects.hashCode(this.sender);
439 return hash;
440 }
441 }
442}
static String getStringOrNull(BlackboardArtifact artifact, Type attributeType)
static Long getLongOrNull(BlackboardArtifact artifact, Type attributeType)
List< RecentAttachmentDetails > getRecentAttachments(DataSource dataSource, int maxCount)
static RecentAttachmentDetails getRecentAttachment(BlackboardArtifact artifact, SleuthkitCase skCase)
static boolean isMessageArtifact(BlackboardArtifact nodeArtifact)
static< T extends RecentFileDetails > List< T > getSortedLimited(List< T > fileDetails, int limit)
List< RecentFileDetails > getRecentlyOpenedDocuments(DataSource dataSource, int maxCount)
List< RecentDownloadDetails > getRecentDownloads(DataSource dataSource, int maxCount)
static RecentFileDetails getRecentlyOpenedDocument(BlackboardArtifact artifact)
static RecentDownloadDetails getRecentDownload(BlackboardArtifact artifact)

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