Autopsy  4.20.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
UserActivitySummary.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.io.File;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collection;
25 import java.util.Collections;
26 import java.util.Comparator;
27 import java.util.Date;
28 import java.util.HashMap;
29 import java.util.HashSet;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Set;
33 import java.util.function.Function;
34 import java.util.logging.Level;
35 import java.util.stream.Collectors;
36 import java.util.stream.Stream;
37 import org.apache.commons.lang3.StringUtils;
38 import org.apache.commons.lang3.tuple.Pair;
39 import org.openide.util.NbBundle.Messages;
41 import org.sleuthkit.datamodel.BlackboardArtifact;
42 import org.sleuthkit.datamodel.BlackboardAttribute;
43 import org.sleuthkit.datamodel.DataSource;
44 import org.sleuthkit.datamodel.TskCoreException;
48 import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
49 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
50 
56 public class UserActivitySummary {
57 
62  private static final List<Function<List<String>, String>> SHORT_FOLDER_MATCHERS = Arrays.asList(
63  // handle Program Files and Program Files (x86) - if true, return the next folder
64  (pathList) -> {
65  if (pathList.size() < 2) {
66  return null;
67  }
68 
69  String rootParent = pathList.get(0).toUpperCase();
70  if ("PROGRAM FILES".equals(rootParent) || "PROGRAM FILES (X86)".equals(rootParent)) {
71  return pathList.get(1);
72  } else {
73  return null;
74  }
75  },
76  // if there is a folder named "APPLICATION DATA" or "APPDATA"
77  (pathList) -> {
78  for (String pathEl : pathList) {
79  String uppered = pathEl.toUpperCase();
80  if ("APPLICATION DATA".equals(uppered) || "APPDATA".equals(uppered)) {
81  return "AppData";
82  }
83  }
84  return null;
85  }
86  );
87 
88  private static final BlackboardArtifact.Type TYPE_DEVICE_ATTACHED = new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_DEVICE_ATTACHED);
89  private static final BlackboardArtifact.Type TYPE_WEB_HISTORY = new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_WEB_HISTORY);
90 
91  private static final BlackboardAttribute.Type TYPE_DATETIME = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME);
92  private static final BlackboardAttribute.Type TYPE_DATETIME_ACCESSED = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED);
93  private static final BlackboardAttribute.Type TYPE_DEVICE_ID = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DEVICE_ID);
94  private static final BlackboardAttribute.Type TYPE_DEVICE_MAKE = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DEVICE_MAKE);
95  private static final BlackboardAttribute.Type TYPE_DEVICE_MODEL = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL);
96  private static final BlackboardAttribute.Type TYPE_MESSAGE_TYPE = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE);
97  private static final BlackboardAttribute.Type TYPE_TEXT = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_TEXT);
98  private static final BlackboardAttribute.Type TYPE_DATETIME_RCVD = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_RCVD);
99  private static final BlackboardAttribute.Type TYPE_DATETIME_SENT = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_SENT);
100  private static final BlackboardAttribute.Type TYPE_DATETIME_START = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_START);
101  private static final BlackboardAttribute.Type TYPE_DATETIME_END = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_END);
102  private static final BlackboardAttribute.Type TYPE_DOMAIN = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DOMAIN);
103  private static final BlackboardAttribute.Type TYPE_PROG_NAME = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PROG_NAME);
104  private static final BlackboardAttribute.Type TYPE_PATH = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PATH);
105  private static final BlackboardAttribute.Type TYPE_COUNT = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_COUNT);
106 
107  private static final String NTOS_BOOT_IDENTIFIER = "NTOSBOOT";
108  private static final String WINDOWS_PREFIX = "/WINDOWS";
109 
110  private static final Comparator<TopAccountResult> TOP_ACCOUNT_RESULT_DATE_COMPARE = (a, b) -> a.getLastAccessed().compareTo(b.getLastAccessed());
111  private static final Comparator<TopWebSearchResult> TOP_WEBSEARCH_RESULT_DATE_COMPARE = (a, b) -> a.getLastAccessed().compareTo(b.getLastAccessed());
112 
117  private static final Comparator<TopProgramsResult> TOP_PROGRAMS_RESULT_COMPARE = (a, b) -> {
118  // first priority for sorting is the run times
119  // if non-0, this is the return value for the comparator
120  int runTimesCompare = nullableCompare(a.getRunTimes(), b.getRunTimes());
121  if (runTimesCompare != 0) {
122  return -runTimesCompare;
123  }
124 
125  // second priority for sorting is the last run date
126  // if non-0, this is the return value for the comparator
127  int lastRunCompare = nullableCompare(
128  a.getLastAccessed() == null ? null : a.getLastAccessed().getTime(),
129  b.getLastAccessed() == null ? null : b.getLastAccessed().getTime());
130 
131  if (lastRunCompare != 0) {
132  return -lastRunCompare;
133  }
134 
135  // otherwise sort alphabetically
136  return (a.getProgramName() == null ? "" : a.getProgramName())
137  .compareToIgnoreCase((b.getProgramName() == null ? "" : b.getProgramName()));
138  };
139 
140  private static final Set<String> DEVICE_EXCLUDE_LIST = new HashSet<>(Arrays.asList("ROOT_HUB", "ROOT_HUB20"));
141  private static final Set<String> DOMAIN_EXCLUDE_LIST = new HashSet<>(Arrays.asList("127.0.0.1", "LOCALHOST"));
142 
143  private static final long MS_PER_DAY = 1000 * 60 * 60 * 24;
144  private static final long DOMAIN_WINDOW_DAYS = 30;
145  private static final long DOMAIN_WINDOW_MS = DOMAIN_WINDOW_DAYS * MS_PER_DAY;
146 
149  private final java.util.logging.Logger logger;
150 
157  }
158 
169  SleuthkitCaseProvider provider,
170  TextTranslationService translationService,
171  java.util.logging.Logger logger) {
172 
173  this.caseProvider = provider;
174  this.translationService = translationService;
175  this.logger = logger;
176  }
177 
183  private static void assertValidCount(int count) {
184  if (count <= 0) {
185  throw new IllegalArgumentException("Count must be greater than 0");
186  }
187  }
188 
197  public static String getShortFolderName(String strPath, String applicationName) {
198  if (strPath == null) {
199  return "";
200  }
201 
202  List<String> pathEls = new ArrayList<>(Arrays.asList(applicationName));
203 
204  File file = new File(strPath);
205  while (file != null && org.apache.commons.lang.StringUtils.isNotBlank(file.getName())) {
206  pathEls.add(file.getName());
207  file = file.getParentFile();
208  }
209 
210  Collections.reverse(pathEls);
211 
212  for (Function<List<String>, String> matchEntry : SHORT_FOLDER_MATCHERS) {
213  String result = matchEntry.apply(pathEls);
214  if (org.apache.commons.lang.StringUtils.isNotBlank(result)) {
215  return result;
216  }
217  }
218 
219  return "";
220  }
221 
232  public List<TopDomainsResult> getRecentDomains(DataSource dataSource, int count) throws TskCoreException, SleuthkitCaseProviderException {
233  assertValidCount(count);
234 
235  if (dataSource == null) {
236  return Collections.emptyList();
237  }
238 
239  Pair<Long, Map<String, List<Pair<BlackboardArtifact, Long>>>> mostRecentAndGroups = getDomainGroupsAndMostRecent(dataSource);
240  // if no recent domains, return accordingly
241  if (mostRecentAndGroups.getKey() == null || mostRecentAndGroups.getValue().size() == 0) {
242  return Collections.emptyList();
243  }
244 
245  final long mostRecentMs = mostRecentAndGroups.getLeft();
246  Map<String, List<Pair<BlackboardArtifact, Long>>> groups = mostRecentAndGroups.getRight();
247 
248  return groups.entrySet().stream()
249  .map(entry -> getDomainsResult(entry.getKey(), entry.getValue(), mostRecentMs))
250  .filter(result -> result != null)
251  // sort by number of visit times in those 30 days (max to min)
252  .sorted((a, b) -> -Long.compare(a.getVisitTimes(), b.getVisitTimes()))
253  // limit the result number to the parameter provided
254  .limit(count)
255  .collect(Collectors.toList());
256  }
257 
270  private TopDomainsResult getDomainsResult(String domain, List<Pair<BlackboardArtifact, Long>> visits, long mostRecentMs) {
271  long visitCount = 0;
272  Long thisMostRecentMs = null;
273  BlackboardArtifact thisMostRecentArtifact = null;
274 
275  for (Pair<BlackboardArtifact, Long> visitInstance : visits) {
276  BlackboardArtifact artifact = visitInstance.getLeft();
277  Long visitMs = visitInstance.getRight();
278  // make sure that visit is within window of mostRecentMS; otherwise skip it.
279  if (visitMs == null || visitMs + DOMAIN_WINDOW_MS < mostRecentMs) {
280  continue;
281  }
282 
283  // if visit is within window, increment the count and get most recent
284  visitCount++;
285  if (thisMostRecentMs == null || visitMs > thisMostRecentMs) {
286  thisMostRecentMs = visitMs;
287  thisMostRecentArtifact = artifact;
288  }
289  thisMostRecentMs = getMax(thisMostRecentMs, visitMs);
290  }
291 
292  // if there are no visits within the window, return null
293  if (visitCount <= 0 || thisMostRecentMs == null) {
294  return null;
295  } else {
296  // create a top domain result with the domain, count, and most recent visit date
297  return new TopDomainsResult(domain, visitCount, new Date(thisMostRecentMs), thisMostRecentArtifact);
298  }
299  }
300 
315  private Pair<Long, Map<String, List<Pair<BlackboardArtifact, Long>>>> getDomainGroupsAndMostRecent(DataSource dataSource) throws TskCoreException, SleuthkitCaseProviderException {
316  List<BlackboardArtifact> artifacts = DataSourceInfoUtilities.getArtifacts(caseProvider.get(), TYPE_WEB_HISTORY,
318 
319  Long mostRecentMs = null;
320  Map<String, List<Pair<BlackboardArtifact, Long>>> domainVisits = new HashMap<>();
321 
322  for (BlackboardArtifact art : artifacts) {
323  Long artifactDateSecs = DataSourceInfoUtilities.getLongOrNull(art, TYPE_DATETIME_ACCESSED);
325 
326  // if there isn't a last access date or domain for this artifact, it can be ignored.
327  // Also, ignore the loopback address.
328  if (artifactDateSecs == null || StringUtils.isBlank(domain) || DOMAIN_EXCLUDE_LIST.contains(domain.toUpperCase().trim())) {
329  continue;
330  }
331 
332  Long artifactDateMs = artifactDateSecs * 1000;
333 
334  // update the most recent visit date overall
335  mostRecentMs = getMax(mostRecentMs, artifactDateMs);
336 
337  //Normalize the domain to lower case.
338  domain = domain.toLowerCase().trim();
339 
340  // add this visit date to the list of dates for the domain
341  List<Pair<BlackboardArtifact, Long>> domainVisitList = domainVisits.get(domain);
342  if (domainVisitList == null) {
343  domainVisitList = new ArrayList<>();
344  domainVisits.put(domain, domainVisitList);
345  }
346 
347  domainVisitList.add(Pair.of(art, artifactDateMs));
348  }
349 
350  return Pair.of(mostRecentMs, domainVisits);
351  }
352 
361  private static Long getMax(Long num1, Long num2) {
362  if (num1 == null) {
363  return num2;
364  } else if (num2 == null) {
365  return num1;
366  } else {
367  return num2 > num1 ? num2 : num1;
368  }
369  }
370 
379  private static TopWebSearchResult getWebSearchResult(BlackboardArtifact artifact) {
380  String searchString = DataSourceInfoUtilities.getStringOrNull(artifact, TYPE_TEXT);
381  Date dateAccessed = DataSourceInfoUtilities.getDateOrNull(artifact, TYPE_DATETIME_ACCESSED);
382  return (StringUtils.isNotBlank(searchString) && dateAccessed != null)
383  ? new TopWebSearchResult(searchString, dateAccessed, artifact)
384  : null;
385  }
386 
402  public List<TopWebSearchResult> getMostRecentWebSearches(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException {
403  assertValidCount(count);
404 
405  if (dataSource == null) {
406  return Collections.emptyList();
407  }
408 
409  // get the artifacts
410  List<BlackboardArtifact> webSearchArtifacts = caseProvider.get().getBlackboard()
411  .getArtifacts(ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID(), dataSource.getId());
412 
413  // group by search string (case insensitive)
414  Collection<TopWebSearchResult> resultGroups = webSearchArtifacts
415  .stream()
416  // get items where search string and date is not null
418  // remove null records
419  .filter(result -> result != null)
420  // get the latest message for each search string
421  .collect(Collectors.toMap(
422  (result) -> result.getSearchString().toUpperCase(),
423  result -> result,
424  (result1, result2) -> TOP_WEBSEARCH_RESULT_DATE_COMPARE.compare(result1, result2) >= 0 ? result1 : result2))
425  .values();
426 
427  // get the most recent date for each search term
428  List<TopWebSearchResult> results = resultGroups
429  .stream()
430  // get most recent searches first
431  .sorted(TOP_WEBSEARCH_RESULT_DATE_COMPARE.reversed())
432  .limit(count)
433  // get as list
434  .collect(Collectors.toList());
435 
436  // get translation if possible
437  if (translationService.hasProvider()) {
438  for (TopWebSearchResult result : results) {
439  result.setTranslatedResult(getTranslationOrNull(result.getSearchString()));
440  }
441  }
442 
443  return results;
444  }
445 
455  private String getTranslationOrNull(String original) {
456  if (!translationService.hasProvider() || StringUtils.isBlank(original)) {
457  return null;
458  }
459 
460  String translated = null;
461  try {
462  translated = translationService.translate(original);
464  logger.log(Level.WARNING, String.format("There was an error translating text: '%s'", original), ex);
465  }
466 
467  // if there is no translation or the translation is the same as the original, return null.
468  if (StringUtils.isBlank(translated)
469  || translated.toUpperCase().trim().equals(original.toUpperCase().trim())) {
470 
471  return null;
472  }
473 
474  return translated;
475  }
476 
487  if (r2.getLastAccessed()== null) {
488  return r1;
489  }
490 
491  if (r1.getLastAccessed() == null) {
492  return r2;
493  }
494 
495  return r1.getLastAccessed().compareTo(r2.getLastAccessed()) >= 0 ? r1 : r2;
496  }
497 
512  public List<TopDeviceAttachedResult> getRecentDevices(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException {
513  assertValidCount(count);
514 
515  if (dataSource == null) {
516  return Collections.emptyList();
517  }
518 
519  Collection<TopDeviceAttachedResult> results = DataSourceInfoUtilities.getArtifacts(caseProvider.get(), TYPE_DEVICE_ATTACHED,
521  .stream()
522  .map(artifact -> {
523  return new TopDeviceAttachedResult(
525  DataSourceInfoUtilities.getDateOrNull(artifact, TYPE_DATETIME),
528  artifact
529  );
530  })
531  // remove Root Hub identifier
532  .filter(result -> {
533  return result.getDeviceId() == null
534  || result.getDeviceModel() == null
535  || !DEVICE_EXCLUDE_LIST.contains(result.getDeviceModel().trim().toUpperCase());
536  })
537  .collect(Collectors.toMap(result -> result.getDeviceId(), result -> result, (r1, r2) -> getMostRecentDevice(r1, r2)))
538  .values();
539 
540  return results.stream()
541  .limit(count)
542  .collect(Collectors.toList());
543  }
544 
553  private static TopAccountResult getMessageAccountResult(BlackboardArtifact artifact) {
555  Date date = DataSourceInfoUtilities.getDateOrNull(artifact, TYPE_DATETIME);
556  return (StringUtils.isNotBlank(type) && date != null)
557  ? new TopAccountResult(type, date, artifact)
558  : null;
559  }
560 
572  private static TopAccountResult getAccountResult(BlackboardArtifact artifact, String messageType, BlackboardAttribute.Type... dateAttrs) {
573  String type = messageType;
574 
575  Date latestDate = null;
576  if (dateAttrs != null) {
577  latestDate = Stream.of(dateAttrs)
578  .map((attr) -> DataSourceInfoUtilities.getDateOrNull(artifact, attr))
579  .filter((date) -> date != null)
580  .max((a, b) -> a.compareTo(b))
581  .orElse(null);
582  }
583 
584  return (StringUtils.isNotBlank(type) && latestDate != null)
585  ? new TopAccountResult(type, latestDate, artifact)
586  : null;
587  }
588 
603  @Messages({
604  "DataSourceUserActivitySummary_getRecentAccounts_emailMessage=Email Message",
605  "DataSourceUserActivitySummary_getRecentAccounts_calllogMessage=Call Log",})
606  public List<TopAccountResult> getRecentAccounts(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException {
607  assertValidCount(count);
608 
609  if (dataSource == null) {
610  return Collections.emptyList();
611  }
612 
613  Stream<TopAccountResult> messageResults = caseProvider.get().getBlackboard().getArtifacts(ARTIFACT_TYPE.TSK_MESSAGE.getTypeID(), dataSource.getId())
614  .stream()
615  .map((art) -> getMessageAccountResult(art));
616 
617  Stream<TopAccountResult> emailResults = caseProvider.get().getBlackboard().getArtifacts(ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID(), dataSource.getId())
618  .stream()
619  .map((art) -> {
620  return getAccountResult(
621  art,
622  Bundle.DataSourceUserActivitySummary_getRecentAccounts_emailMessage(),
625  });
626 
627  Stream<TopAccountResult> calllogResults = caseProvider.get().getBlackboard().getArtifacts(ARTIFACT_TYPE.TSK_CALLLOG.getTypeID(), dataSource.getId())
628  .stream()
629  .map((art) -> {
630  return getAccountResult(
631  art,
632  Bundle.DataSourceUserActivitySummary_getRecentAccounts_calllogMessage(),
635  });
636 
637  Stream<TopAccountResult> allResults = Stream.concat(messageResults, Stream.concat(emailResults, calllogResults));
638 
639  // get them grouped by account type
640  Collection<TopAccountResult> groupedResults = allResults
641  // remove null records
642  .filter(result -> result != null)
643  // get these messages grouped by account type and get the most recent of each type
644  .collect(Collectors.toMap(
645  result -> result.getAccountType(),
646  result -> result,
647  (result1, result2) -> TOP_ACCOUNT_RESULT_DATE_COMPARE.compare(result1, result2) >= 0 ? result1 : result2))
648  .values();
649 
650  // get account type sorted by most recent date
651  return groupedResults
652  .stream()
653  // get most recent accounts accessed
654  .sorted(TOP_ACCOUNT_RESULT_DATE_COMPARE.reversed())
655  // limit to count
656  .limit(count)
657  // get as list
658  .collect(Collectors.toList());
659  }
660 
668  private TopProgramsResult getTopProgramsResult(BlackboardArtifact artifact) {
669  String programName = DataSourceInfoUtilities.getStringOrNull(artifact, TYPE_PROG_NAME);
670 
671  // ignore items with no name or a ntos boot identifier
672  if (StringUtils.isBlank(programName) || NTOS_BOOT_IDENTIFIER.equalsIgnoreCase(programName)) {
673  return null;
674  }
675 
676  String path = DataSourceInfoUtilities.getStringOrNull(artifact, TYPE_PATH);
677 
678  // ignore windows directory
679  if (StringUtils.startsWithIgnoreCase(path, WINDOWS_PREFIX)) {
680  return null;
681  }
682 
683  Integer count = DataSourceInfoUtilities.getIntOrNull(artifact, TYPE_COUNT);
684  Long longCount = (count == null) ? null : (long) count;
685 
686  return new TopProgramsResult(
687  programName,
688  path,
689  longCount,
691  artifact
692  );
693  }
694 
703  private static Date getMax(Date date1, Date date2) {
704  if (date1 == null) {
705  return date2;
706  } else if (date2 == null) {
707  return date1;
708  } else {
709  return date1.compareTo(date2) > 0 ? date1 : date2;
710  }
711  }
712 
722  private static int nullableCompare(Long long1, Long long2) {
723  if (long1 == null && long2 == null) {
724  return 0;
725  } else if (long1 != null && long2 == null) {
726  return 1;
727  } else if (long1 == null && long2 != null) {
728  return -1;
729  }
730 
731  return Long.compare(long1, long2);
732  }
733 
741  private static boolean isPositiveNum(Long longNum) {
742  return longNum != null && longNum > 0;
743  }
744 
764  public List<TopProgramsResult> getTopPrograms(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException {
765  assertValidCount(count);
766 
767  if (dataSource == null) {
768  return Collections.emptyList();
769  }
770 
771  // Get TopProgramsResults for each TSK_PROG_RUN artifact
772  Collection<TopProgramsResult> results = caseProvider.get().getBlackboard().getArtifacts(ARTIFACT_TYPE.TSK_PROG_RUN.getTypeID(), dataSource.getId())
773  .stream()
774  // convert to a TopProgramsResult object or null if missing critical information
775  .map((art) -> getTopProgramsResult(art))
776  // remove any null items
777  .filter((res) -> res != null)
778  // group by the program name and program path
779  // The value will be a TopProgramsResult with the max run times
780  // and most recent last run date for each program name / program path pair.
781  .collect(Collectors.toMap(
782  res -> Pair.of(
783  res.getProgramName() == null ? null : res.getProgramName().toUpperCase(),
784  res.getProgramPath() == null ? null : res.getProgramPath().toUpperCase()),
785  res -> res,
786  (res1, res2) -> {
787  Long maxRunTimes = getMax(res1.getRunTimes(), res2.getRunTimes());
788  Date maxDate = getMax(res1.getLastAccessed(), res2.getLastAccessed());
789  TopProgramsResult maxResult = TOP_PROGRAMS_RESULT_COMPARE.compare(res1, res2) >= 0 ? res1 : res2;
790  return new TopProgramsResult(
791  maxResult.getProgramName(),
792  maxResult.getProgramPath(),
793  maxRunTimes,
794  maxDate,
795  maxResult.getArtifact());
796  })).values();
797 
798  List<TopProgramsResult> orderedResults = results.stream()
799  .sorted(TOP_PROGRAMS_RESULT_COMPARE)
800  .collect(Collectors.toList());
801 
802  // only limit the list to count if there is no last run date and no run times.
803  if (!orderedResults.isEmpty()) {
804  TopProgramsResult topResult = orderedResults.get(0);
805  // if run times / last run information is available, the first item should have some value,
806  // and then the items should be limited accordingly.
807  if (isPositiveNum(topResult.getRunTimes())
808  || (topResult.getLastAccessed() != null && isPositiveNum(topResult.getLastAccessed().getTime()))) {
809  return orderedResults.stream().limit(count).collect(Collectors.toList());
810  }
811  }
812 
813  // otherwise return the alphabetized list with no limit applied.
814  return orderedResults;
815  }
816 
821  public static class LastAccessedArtifact {
822 
823  private final Date lastAccessed;
824  private final BlackboardArtifact artifact;
825 
832  public LastAccessedArtifact(Date lastAccessed, BlackboardArtifact artifact) {
833  this.lastAccessed = lastAccessed;
834  this.artifact = artifact;
835  }
836 
840  public Date getLastAccessed() {
841  return lastAccessed;
842  }
843 
847  public BlackboardArtifact getArtifact() {
848  return artifact;
849  }
850  }
851 
855  public static class TopWebSearchResult extends LastAccessedArtifact {
856 
857  private final String searchString;
858  private String translatedResult;
859 
867  public TopWebSearchResult(String searchString, Date dateAccessed, BlackboardArtifact artifact) {
868  super(dateAccessed, artifact);
869  this.searchString = searchString;
870  }
871 
875  public String getTranslatedResult() {
876  return translatedResult;
877  }
878 
884  public void setTranslatedResult(String translatedResult) {
885  this.translatedResult = translatedResult;
886  }
887 
891  public String getSearchString() {
892  return searchString;
893  }
894  }
895 
899  public static class TopDeviceAttachedResult extends LastAccessedArtifact {
900 
901  private final String deviceId;
902  private final String deviceMake;
903  private final String deviceModel;
904 
914  public TopDeviceAttachedResult(String deviceId, Date dateAccessed, String deviceMake, String deviceModel, BlackboardArtifact artifact) {
915  super(dateAccessed, artifact);
916  this.deviceId = deviceId;
917  this.deviceMake = deviceMake;
918  this.deviceModel = deviceModel;
919  }
920 
924  public String getDeviceId() {
925  return deviceId;
926  }
927 
931  public String getDeviceMake() {
932  return deviceMake;
933  }
934 
938  public String getDeviceModel() {
939  return deviceModel;
940  }
941  }
942 
947  public static class TopAccountResult extends LastAccessedArtifact {
948 
949  private final String accountType;
950 
958  public TopAccountResult(String accountType, Date lastAccess, BlackboardArtifact artifact) {
959  super(lastAccess, artifact);
960  this.accountType = accountType;
961  }
962 
966  public String getAccountType() {
967  return accountType;
968  }
969  }
970 
974  public static class TopDomainsResult extends LastAccessedArtifact {
975 
976  private final String domain;
977  private final Long visitTimes;
978 
987  public TopDomainsResult(String domain, Long visitTimes, Date lastVisit, BlackboardArtifact artifact) {
988  super(lastVisit, artifact);
989  this.domain = domain;
990  this.visitTimes = visitTimes;
991  }
992 
996  public String getDomain() {
997  return domain;
998  }
999 
1003  public Long getVisitTimes() {
1004  return visitTimes;
1005  }
1006  }
1007 
1011  public static class TopProgramsResult extends LastAccessedArtifact {
1012 
1013  private final String programName;
1014  private final String programPath;
1015  private final Long runTimes;
1016 
1025  TopProgramsResult(String programName, String programPath, Long runTimes, Date lastRun, BlackboardArtifact artifact) {
1026  super(lastRun, artifact);
1027  this.programName = programName;
1028  this.programPath = programPath;
1029  this.runTimes = runTimes;
1030  }
1031 
1035  public String getProgramName() {
1036  return programName;
1037  }
1038 
1042  public String getProgramPath() {
1043  return programPath;
1044  }
1045 
1049  public Long getRunTimes() {
1050  return runTimes;
1051  }
1052  }
1053 }
static final Comparator< TopWebSearchResult > TOP_WEBSEARCH_RESULT_DATE_COMPARE
TopDomainsResult(String domain, Long visitTimes, Date lastVisit, BlackboardArtifact artifact)
static TopWebSearchResult getWebSearchResult(BlackboardArtifact artifact)
TopDomainsResult getDomainsResult(String domain, List< Pair< BlackboardArtifact, Long >> visits, long mostRecentMs)
List< TopAccountResult > getRecentAccounts(DataSource dataSource, int count)
UserActivitySummary(SleuthkitCaseProvider provider, TextTranslationService translationService, java.util.logging.Logger logger)
List< TopWebSearchResult > getMostRecentWebSearches(DataSource dataSource, int count)
static TopAccountResult getMessageAccountResult(BlackboardArtifact artifact)
List< TopDeviceAttachedResult > getRecentDevices(DataSource dataSource, int count)
TopAccountResult(String accountType, Date lastAccess, BlackboardArtifact artifact)
TopProgramsResult getTopProgramsResult(BlackboardArtifact artifact)
TopDeviceAttachedResult getMostRecentDevice(TopDeviceAttachedResult r1, TopDeviceAttachedResult r2)
static List< BlackboardArtifact > getArtifacts(SleuthkitCase skCase, BlackboardArtifact.Type artifactType, DataSource dataSource, BlackboardAttribute.Type attributeType, SortOrder sortOrder)
static final Comparator< TopAccountResult > TOP_ACCOUNT_RESULT_DATE_COMPARE
TopWebSearchResult(String searchString, Date dateAccessed, BlackboardArtifact artifact)
List< TopProgramsResult > getTopPrograms(DataSource dataSource, int count)
static Long getLongOrNull(BlackboardArtifact artifact, Type attributeType)
Pair< Long, Map< String, List< Pair< BlackboardArtifact, Long > > > > getDomainGroupsAndMostRecent(DataSource dataSource)
static Integer getIntOrNull(BlackboardArtifact artifact, Type attributeType)
List< TopDomainsResult > getRecentDomains(DataSource dataSource, int count)
static final Comparator< TopProgramsResult > TOP_PROGRAMS_RESULT_COMPARE
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
TopDeviceAttachedResult(String deviceId, Date dateAccessed, String deviceMake, String deviceModel, BlackboardArtifact artifact)
static Date getDateOrNull(BlackboardArtifact artifact, Type attributeType)
static String getShortFolderName(String strPath, String applicationName)
static String getStringOrNull(BlackboardArtifact artifact, Type attributeType)
static final List< Function< List< String >, String > > SHORT_FOLDER_MATCHERS
static TopAccountResult getAccountResult(BlackboardArtifact artifact, String messageType, BlackboardAttribute.Type...dateAttrs)

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.