19 package org.sleuthkit.autopsy.datasourcesummary.datamodel;
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;
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;
65 if (pathList.size() < 2) {
69 String rootParent = pathList.get(0).toUpperCase();
70 if (
"PROGRAM FILES".equals(rootParent) ||
"PROGRAM FILES (X86)".equals(rootParent)) {
71 return pathList.get(1);
78 for (String pathEl : pathList) {
79 String uppered = pathEl.toUpperCase();
80 if (
"APPLICATION DATA".equals(uppered) ||
"APPDATA".equals(uppered)) {
120 int runTimesCompare =
nullableCompare(a.getRunTimes(), b.getRunTimes());
121 if (runTimesCompare != 0) {
122 return -runTimesCompare;
128 a.getLastAccessed() == null ? null : a.getLastAccessed().getTime(),
129 b.getLastAccessed() == null ? null : b.getLastAccessed().getTime());
131 if (lastRunCompare != 0) {
132 return -lastRunCompare;
136 return (a.getProgramName() == null ?
"" : a.getProgramName())
137 .compareToIgnoreCase((b.getProgramName() == null ?
"" : b.getProgramName()));
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"));
149 private final java.util.logging.Logger
logger;
171 java.util.logging.Logger
logger) {
173 this.caseProvider = provider;
185 throw new IllegalArgumentException(
"Count must be greater than 0");
198 if (strPath == null) {
202 List<String> pathEls =
new ArrayList<>(Arrays.asList(applicationName));
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();
210 Collections.reverse(pathEls);
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)) {
235 if (dataSource == null) {
236 return Collections.emptyList();
241 if (mostRecentAndGroups.getKey() == null || mostRecentAndGroups.getValue().size() == 0) {
242 return Collections.emptyList();
245 final long mostRecentMs = mostRecentAndGroups.getLeft();
246 Map<String, List<Pair<BlackboardArtifact, Long>>> groups = mostRecentAndGroups.getRight();
248 return groups.entrySet().stream()
249 .map(entry ->
getDomainsResult(entry.getKey(), entry.getValue(), mostRecentMs))
250 .filter(result -> result != null)
252 .sorted((a, b) -> -Long.compare(a.getVisitTimes(), b.getVisitTimes()))
255 .collect(Collectors.toList());
272 Long thisMostRecentMs = null;
275 for (Pair<BlackboardArtifact, Long> visitInstance : visits) {
277 Long visitMs = visitInstance.getRight();
279 if (visitMs == null || visitMs + DOMAIN_WINDOW_MS < mostRecentMs) {
285 if (thisMostRecentMs == null || visitMs > thisMostRecentMs) {
286 thisMostRecentMs = visitMs;
287 thisMostRecentArtifact = artifact;
289 thisMostRecentMs =
getMax(thisMostRecentMs, visitMs);
293 if (visitCount <= 0 || thisMostRecentMs == null) {
297 return new TopDomainsResult(domain, visitCount,
new Date(thisMostRecentMs), thisMostRecentArtifact);
319 Long mostRecentMs = null;
320 Map<String, List<Pair<BlackboardArtifact, Long>>> domainVisits =
new HashMap<>();
328 if (artifactDateSecs == null || StringUtils.isBlank(domain) || DOMAIN_EXCLUDE_LIST.contains(domain.toUpperCase().trim())) {
332 Long artifactDateMs = artifactDateSecs * 1000;
335 mostRecentMs =
getMax(mostRecentMs, artifactDateMs);
338 domain = domain.toLowerCase().trim();
341 List<Pair<BlackboardArtifact, Long>> domainVisitList = domainVisits.get(domain);
342 if (domainVisitList == null) {
343 domainVisitList =
new ArrayList<>();
344 domainVisits.put(domain, domainVisitList);
347 domainVisitList.add(Pair.of(art, artifactDateMs));
350 return Pair.of(mostRecentMs, domainVisits);
361 private static Long
getMax(Long num1, Long num2) {
364 }
else if (num2 == null) {
367 return num2 > num1 ? num2 : num1;
382 return (StringUtils.isNotBlank(searchString) && dateAccessed != null)
405 if (dataSource == null) {
406 return Collections.emptyList();
410 List<BlackboardArtifact> webSearchArtifacts = caseProvider.
get().
getBlackboard()
414 Collection<TopWebSearchResult> resultGroups = webSearchArtifacts
419 .filter(result -> result != null)
421 .collect(Collectors.toMap(
422 (result) -> result.getSearchString().toUpperCase(),
424 (result1, result2) -> TOP_WEBSEARCH_RESULT_DATE_COMPARE.compare(result1, result2) >= 0 ? result1 : result2))
428 List<TopWebSearchResult> results = resultGroups
431 .sorted(TOP_WEBSEARCH_RESULT_DATE_COMPARE.reversed())
434 .collect(Collectors.toList());
456 if (!translationService.
hasProvider() || StringUtils.isBlank(original)) {
460 String translated = null;
462 translated = translationService.
translate(original);
464 logger.log(Level.WARNING, String.format(
"There was an error translating text: '%s'", original), ex);
468 if (StringUtils.isBlank(translated)
469 || translated.toUpperCase().trim().equals(original.toUpperCase().trim())) {
512 public List<TopDeviceAttachedResult>
getRecentDevices(
DataSource dataSource,
int count)
throws SleuthkitCaseProviderException, TskCoreException {
515 if (dataSource == null) {
516 return Collections.emptyList();
533 return result.getDeviceId() == null
534 || result.getDeviceModel() == null
535 || !DEVICE_EXCLUDE_LIST.contains(result.getDeviceModel().trim().toUpperCase());
537 .collect(Collectors.toMap(result -> result.getDeviceId(), result -> result, (r1, r2) ->
getMostRecentDevice(r1, r2)))
540 return results.stream()
542 .collect(Collectors.toList());
556 return (StringUtils.isNotBlank(type) && date != null)
573 String type = messageType;
575 Date latestDate = null;
576 if (dateAttrs != null) {
577 latestDate = Stream.of(dateAttrs)
579 .filter((date) -> date != null)
580 .max((a, b) -> a.compareTo(b))
584 return (StringUtils.isNotBlank(type) && latestDate != null)
604 "DataSourceUserActivitySummary_getRecentAccounts_emailMessage=Email Message",
605 "DataSourceUserActivitySummary_getRecentAccounts_calllogMessage=Call Log",})
609 if (dataSource == null) {
610 return Collections.emptyList();
622 Bundle.DataSourceUserActivitySummary_getRecentAccounts_emailMessage(),
632 Bundle.DataSourceUserActivitySummary_getRecentAccounts_calllogMessage(),
637 Stream<TopAccountResult> allResults = Stream.concat(messageResults, Stream.concat(emailResults, calllogResults));
640 Collection<TopAccountResult> groupedResults = allResults
642 .filter(result -> result != null)
644 .collect(Collectors.toMap(
645 result -> result.getAccountType(),
647 (result1, result2) -> TOP_ACCOUNT_RESULT_DATE_COMPARE.compare(result1, result2) >= 0 ? result1 : result2))
651 return groupedResults
654 .sorted(TOP_ACCOUNT_RESULT_DATE_COMPARE.reversed())
658 .collect(Collectors.toList());
672 if (StringUtils.isBlank(programName) || NTOS_BOOT_IDENTIFIER.equalsIgnoreCase(programName)) {
679 if (StringUtils.startsWithIgnoreCase(path, WINDOWS_PREFIX)) {
684 Long longCount = (count == null) ? null : (
long) count;
703 private static Date
getMax(Date date1, Date date2) {
706 }
else if (date2 == null) {
709 return date1.compareTo(date2) > 0 ? date1 : date2;
723 if (long1 == null && long2 == null) {
725 }
else if (long1 != null && long2 == null) {
727 }
else if (long1 == null && long2 != null) {
731 return Long.compare(long1, long2);
742 return longNum != null && longNum > 0;
764 public List<TopProgramsResult>
getTopPrograms(
DataSource dataSource,
int count)
throws SleuthkitCaseProviderException, TskCoreException {
767 if (dataSource == null) {
768 return Collections.emptyList();
777 .filter((res) -> res != null)
781 .collect(Collectors.toMap(
783 res.getProgramName() == null ? null : res.getProgramName().toUpperCase(),
784 res.getProgramPath() == null ? null : res.getProgramPath().toUpperCase()),
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;
791 maxResult.getProgramName(),
792 maxResult.getProgramPath(),
795 maxResult.getArtifact());
798 List<TopProgramsResult> orderedResults = results.stream()
799 .sorted(TOP_PROGRAMS_RESULT_COMPARE)
800 .collect(Collectors.toList());
803 if (!orderedResults.isEmpty()) {
809 return orderedResults.stream().limit(count).collect(Collectors.toList());
814 return orderedResults;
868 super(dateAccessed, artifact);
915 super(dateAccessed, artifact);
959 super(lastAccess, artifact);
988 super(lastVisit, artifact);
1026 super(lastRun, artifact);
static final BlackboardAttribute.Type TYPE_DATETIME
static final Comparator< TopWebSearchResult > TOP_WEBSEARCH_RESULT_DATE_COMPARE
TopDomainsResult(String domain, Long visitTimes, Date lastVisit, BlackboardArtifact artifact)
LastAccessedArtifact(Date lastAccessed, BlackboardArtifact artifact)
final java.util.logging.Logger logger
static final BlackboardAttribute.Type TYPE_DEVICE_MODEL
SleuthkitCaseProvider DEFAULT
static Date getMax(Date date1, Date date2)
static final BlackboardAttribute.Type TYPE_DOMAIN
static final BlackboardAttribute.Type TYPE_DEVICE_ID
static TopWebSearchResult getWebSearchResult(BlackboardArtifact artifact)
Blackboard getBlackboard()
static final BlackboardAttribute.Type TYPE_DATETIME_START
synchronized String translate(String input)
TopDomainsResult getDomainsResult(String domain, List< Pair< BlackboardArtifact, Long >> visits, long mostRecentMs)
static final long DOMAIN_WINDOW_MS
static final String WINDOWS_PREFIX
static Long getMax(Long num1, Long num2)
static final Set< String > DEVICE_EXCLUDE_LIST
List< TopAccountResult > getRecentAccounts(DataSource dataSource, int count)
static final BlackboardAttribute.Type TYPE_DEVICE_MAKE
static final BlackboardAttribute.Type TYPE_PATH
UserActivitySummary(SleuthkitCaseProvider provider, TextTranslationService translationService, java.util.logging.Logger logger)
static int nullableCompare(Long long1, Long long2)
List< TopWebSearchResult > getMostRecentWebSearches(DataSource dataSource, int count)
static void assertValidCount(int count)
static TopAccountResult getMessageAccountResult(BlackboardArtifact artifact)
static final Set< String > DOMAIN_EXCLUDE_LIST
static final String NTOS_BOOT_IDENTIFIER
static final BlackboardAttribute.Type TYPE_COUNT
List< TopDeviceAttachedResult > getRecentDevices(DataSource dataSource, int count)
TopAccountResult(String accountType, Date lastAccess, BlackboardArtifact artifact)
TopProgramsResult getTopProgramsResult(BlackboardArtifact artifact)
List< BlackboardArtifact > getArtifacts(int artifactTypeID, long dataSourceObjId)
TopDeviceAttachedResult getMostRecentDevice(TopDeviceAttachedResult r1, TopDeviceAttachedResult r2)
static TextTranslationService getInstance()
String getTranslationOrNull(String original)
final BlackboardArtifact artifact
static final long DOMAIN_WINDOW_DAYS
final TextTranslationService translationService
static List< BlackboardArtifact > getArtifacts(SleuthkitCase skCase, BlackboardArtifact.Type artifactType, DataSource dataSource, BlackboardAttribute.Type attributeType, SortOrder sortOrder)
static final BlackboardAttribute.Type TYPE_DATETIME_SENT
static final long MS_PER_DAY
static final BlackboardAttribute.Type TYPE_DATETIME_ACCESSED
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)
synchronized boolean hasProvider()
static boolean isPositiveNum(Long longNum)
final SleuthkitCaseProvider caseProvider
static Integer getIntOrNull(BlackboardArtifact artifact, Type attributeType)
final String searchString
List< TopDomainsResult > getRecentDomains(DataSource dataSource, int count)
void setTranslatedResult(String translatedResult)
static final BlackboardAttribute.Type TYPE_DATETIME_END
static final Comparator< TopProgramsResult > TOP_PROGRAMS_RESULT_COMPARE
static final BlackboardAttribute.Type TYPE_MESSAGE_TYPE
synchronized static Logger getLogger(String name)
static final BlackboardAttribute.Type TYPE_TEXT
String getTranslatedResult()
static final BlackboardAttribute.Type TYPE_PROG_NAME
TopDeviceAttachedResult(String deviceId, Date dateAccessed, String deviceMake, String deviceModel, BlackboardArtifact artifact)
static final BlackboardArtifact.Type TYPE_DEVICE_ATTACHED
static Date getDateOrNull(BlackboardArtifact artifact, Type attributeType)
static final BlackboardAttribute.Type TYPE_DATETIME_RCVD
static final BlackboardArtifact.Type TYPE_WEB_HISTORY
static String getShortFolderName(String strPath, String applicationName)
static String getStringOrNull(BlackboardArtifact artifact, Type attributeType)
BlackboardArtifact getArtifact()
static final List< Function< List< String >, String > > SHORT_FOLDER_MATCHERS
static TopAccountResult getAccountResult(BlackboardArtifact artifact, String messageType, BlackboardAttribute.Type...dateAttrs)