Autopsy  4.19.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  */
19 package org.sleuthkit.autopsy.datasourcesummary.datamodel;
20 
21 import java.nio.file.Paths;
22 import java.text.DateFormat;
23 import java.text.SimpleDateFormat;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.List;
27 import java.util.Locale;
28 import java.util.Map;
29 import java.util.Objects;
30 import java.util.stream.Collectors;
31 import org.apache.commons.lang.StringUtils;
33 import org.sleuthkit.datamodel.AbstractFile;
34 import org.sleuthkit.datamodel.BlackboardArtifact;
35 import org.sleuthkit.datamodel.BlackboardAttribute;
36 import org.sleuthkit.datamodel.Content;
37 import org.sleuthkit.datamodel.DataSource;
38 import org.sleuthkit.datamodel.SleuthkitCase;
39 import org.sleuthkit.datamodel.TskCoreException;
40 import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
41 
45 public 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 
62  public RecentFilesSummary() {
64  }
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);
110  Long lastOpened = DataSourceInfoUtilities.getLongOrNull(artifact, DATETIME_ACCESSED_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 boolean isMessageArtifact(BlackboardArtifact nodeArtifact)
static RecentDownloadDetails getRecentDownload(BlackboardArtifact artifact)
List< RecentFileDetails > getRecentlyOpenedDocuments(DataSource dataSource, int maxCount)
static< TextendsRecentFileDetails > List< T > getSortedLimited(List< T > fileDetails, int limit)
List< RecentDownloadDetails > getRecentDownloads(DataSource dataSource, int maxCount)
List< RecentAttachmentDetails > getRecentAttachments(DataSource dataSource, int maxCount)
static RecentAttachmentDetails getRecentAttachment(BlackboardArtifact artifact, SleuthkitCase skCase)
static Long getLongOrNull(BlackboardArtifact artifact, Type attributeType)
static RecentFileDetails getRecentlyOpenedDocument(BlackboardArtifact artifact)
static String getStringOrNull(BlackboardArtifact artifact, Type attributeType)

Copyright © 2012-2021 Basis Technology. Generated on: Thu Sep 30 2021
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.