mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-13 08:26:15 +00:00
Merge branch 'develop' of github.com:sleuthkit/autopsy into 7079-messagingDomains
This commit is contained in:
commit
12fea8dbbf
@ -43,9 +43,11 @@ import org.openide.util.NbBundle;
|
|||||||
import org.openide.util.lookup.ServiceProvider;
|
import org.openide.util.lookup.ServiceProvider;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
||||||
import org.sleuthkit.autopsy.discovery.ui.AbstractArtifactDetailsPanel;
|
import org.sleuthkit.autopsy.discovery.ui.AbstractArtifactDetailsPanel;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
|
import org.sleuthkit.datamodel.TimeUtilities;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -116,7 +118,7 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i
|
|||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
logger.log(Level.WARNING, "Unable to get attributes for artifact " + artifact.getArtifactID(), ex);
|
logger.log(Level.WARNING, "Unable to get attributes for artifact " + artifact.getArtifactID(), ex);
|
||||||
}
|
}
|
||||||
updateView(artifact.getArtifactTypeID(), attributeMap, dataSourceName, sourceFileName);
|
updateView(artifact, attributeMap, dataSourceName, sourceFileName);
|
||||||
}
|
}
|
||||||
this.setLayout(this.gridBagLayout);
|
this.setLayout(this.gridBagLayout);
|
||||||
this.revalidate();
|
this.revalidate();
|
||||||
@ -195,7 +197,8 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i
|
|||||||
* the artifact.
|
* the artifact.
|
||||||
*/
|
*/
|
||||||
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||||
private void updateView(Integer artifactTypeId, Map<Integer, List<BlackboardAttribute>> attributeMap, String dataSourceName, String sourceFileName) {
|
private void updateView(BlackboardArtifact artifact, Map<Integer, List<BlackboardAttribute>> attributeMap, String dataSourceName, String sourceFileName) {
|
||||||
|
final Integer artifactTypeId = artifact.getArtifactTypeID();
|
||||||
if (!(artifactTypeId < 1 || artifactTypeId >= Integer.MAX_VALUE)) {
|
if (!(artifactTypeId < 1 || artifactTypeId >= Integer.MAX_VALUE)) {
|
||||||
addHeader(Bundle.GeneralPurposeArtifactViewer_details_attrHeader());
|
addHeader(Bundle.GeneralPurposeArtifactViewer_details_attrHeader());
|
||||||
Integer[] orderingArray = orderingMap.get(artifactTypeId);
|
Integer[] orderingArray = orderingMap.get(artifactTypeId);
|
||||||
@ -206,13 +209,21 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i
|
|||||||
List<BlackboardAttribute> attrList = attributeMap.remove(attrId);
|
List<BlackboardAttribute> attrList = attributeMap.remove(attrId);
|
||||||
if (attrList != null) {
|
if (attrList != null) {
|
||||||
for (BlackboardAttribute bba : attrList) {
|
for (BlackboardAttribute bba : attrList) {
|
||||||
addNameValueRow(bba.getAttributeType().getDisplayName(), bba.getDisplayString());
|
if (bba.getAttributeType().getTypeName().startsWith("TSK_DATETIME")) {
|
||||||
|
addNameValueRow(bba.getAttributeType().getDisplayName(), TimeUtilities.epochToTime(bba.getValueLong(), ContentUtils.getTimeZone(artifact)));
|
||||||
|
} else {
|
||||||
|
addNameValueRow(bba.getAttributeType().getDisplayName(), bba.getDisplayString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int key : attributeMap.keySet()) {
|
for (int key : attributeMap.keySet()) {
|
||||||
for (BlackboardAttribute bba : attributeMap.get(key)) {
|
for (BlackboardAttribute bba : attributeMap.get(key)) {
|
||||||
addNameValueRow(bba.getAttributeType().getDisplayName(), bba.getDisplayString());
|
if (bba.getAttributeType().getTypeName().startsWith("TSK_DATETIME")) {
|
||||||
|
addNameValueRow(bba.getAttributeType().getDisplayName(), TimeUtilities.epochToTime(bba.getValueLong(), ContentUtils.getTimeZone(artifact)));
|
||||||
|
} else {
|
||||||
|
addNameValueRow(bba.getAttributeType().getDisplayName(), bba.getDisplayString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addHeader(Bundle.GeneralPurposeArtifactViewer_details_sourceHeader());
|
addHeader(Bundle.GeneralPurposeArtifactViewer_details_sourceHeader());
|
||||||
|
@ -7,8 +7,8 @@ DiscoveryAttributes.GroupingAttributeType.interestingItem.displayName=Interestin
|
|||||||
DiscoveryAttributes.GroupingAttributeType.keywordList.displayName=Keyword
|
DiscoveryAttributes.GroupingAttributeType.keywordList.displayName=Keyword
|
||||||
DiscoveryAttributes.GroupingAttributeType.mostRecentDate.displayName=Most Recent Activity Date
|
DiscoveryAttributes.GroupingAttributeType.mostRecentDate.displayName=Most Recent Activity Date
|
||||||
DiscoveryAttributes.GroupingAttributeType.none.displayName=None
|
DiscoveryAttributes.GroupingAttributeType.none.displayName=None
|
||||||
DiscoveryAttributes.GroupingAttributeType.numberOfVisits.displayName=Number of Visits
|
|
||||||
DiscoveryAttributes.GroupingAttributeType.object.displayName=Object Detected
|
DiscoveryAttributes.GroupingAttributeType.object.displayName=Object Detected
|
||||||
|
DiscoveryAttributes.GroupingAttributeType.pageViews.displayName=Page Views
|
||||||
DiscoveryAttributes.GroupingAttributeType.parent.displayName=Parent Folder
|
DiscoveryAttributes.GroupingAttributeType.parent.displayName=Parent Folder
|
||||||
DiscoveryAttributes.GroupingAttributeType.previouslyNotable.displayName=Previous Notability
|
DiscoveryAttributes.GroupingAttributeType.previouslyNotable.displayName=Previous Notability
|
||||||
DiscoveryAttributes.GroupingAttributeType.size.displayName=File Size
|
DiscoveryAttributes.GroupingAttributeType.size.displayName=File Size
|
||||||
@ -25,10 +25,10 @@ DiscoveryKeyUtils.InterestingItemGroupKey.noSets=None
|
|||||||
DiscoveryKeyUtils.KeywordListGroupKey.noKeywords=None
|
DiscoveryKeyUtils.KeywordListGroupKey.noKeywords=None
|
||||||
DiscoveryKeyUtils.MostRecentActivityDateGroupKey.noDate=No Date Available
|
DiscoveryKeyUtils.MostRecentActivityDateGroupKey.noDate=No Date Available
|
||||||
DiscoveryKeyUtils.NoGroupingGroupKey.allFiles=All Files
|
DiscoveryKeyUtils.NoGroupingGroupKey.allFiles=All Files
|
||||||
# {0} - totalVisits
|
|
||||||
DiscoveryKeyUtils.NumberOfVisitsGroupKey.displayName={0} visits
|
|
||||||
DiscoveryKeyUtils.NumberOfVisitsGroupKey.noVisits=No visits
|
|
||||||
DiscoveryKeyUtils.ObjectDetectedGroupKey.noSets=None
|
DiscoveryKeyUtils.ObjectDetectedGroupKey.noSets=None
|
||||||
|
# {0} - totalVisits
|
||||||
|
DiscoveryKeyUtils.PageViewsGroupKey.displayName={0} page views
|
||||||
|
DiscoveryKeyUtils.PageViewsGroupKey.noVisits=No page views
|
||||||
# {0} - domain
|
# {0} - domain
|
||||||
# {1} - artifactType
|
# {1} - artifactType
|
||||||
DomainSearchArtifactsRequest.toString.text=Domain: {0} ArtifactType: {1}
|
DomainSearchArtifactsRequest.toString.text=Domain: {0} ArtifactType: {1}
|
||||||
@ -53,6 +53,7 @@ FileSorter.SortingMethod.filetype.displayName=File Type
|
|||||||
FileSorter.SortingMethod.frequency.displayName=Central Repo Frequency
|
FileSorter.SortingMethod.frequency.displayName=Central Repo Frequency
|
||||||
FileSorter.SortingMethod.fullPath.displayName=Full Path
|
FileSorter.SortingMethod.fullPath.displayName=Full Path
|
||||||
FileSorter.SortingMethod.keywordlist.displayName=Keyword List Names
|
FileSorter.SortingMethod.keywordlist.displayName=Keyword List Names
|
||||||
|
FileSorter.SortingMethod.pageViews.displayName=Page Views
|
||||||
ResultFile.score.interestingResult.description=At least one instance of the file has an interesting result associated with it.
|
ResultFile.score.interestingResult.description=At least one instance of the file has an interesting result associated with it.
|
||||||
ResultFile.score.notableFile.description=At least one instance of the file was recognized as notable.
|
ResultFile.score.notableFile.description=At least one instance of the file was recognized as notable.
|
||||||
ResultFile.score.notableTaggedFile.description=At least one instance of the file is tagged with a notable tag.
|
ResultFile.score.notableTaggedFile.description=At least one instance of the file is tagged with a notable tag.
|
||||||
|
@ -730,13 +730,14 @@ public class DiscoveryAttributes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attribute for grouping/sorting by number of visits.
|
* Attribute for grouping/sorting domains by number of page views.
|
||||||
|
* Page views is defined at the number of TSK_WEB_HISTORY artifacts.
|
||||||
*/
|
*/
|
||||||
static class NumberOfVisitsAttribute extends AttributeType {
|
static class PageViewsAttribute extends AttributeType {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DiscoveryKeyUtils.GroupKey getGroupKey(Result result) {
|
public DiscoveryKeyUtils.GroupKey getGroupKey(Result result) {
|
||||||
return new DiscoveryKeyUtils.NumberOfVisitsGroupKey(result);
|
return new DiscoveryKeyUtils.PageViewsGroupKey(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -864,7 +865,7 @@ public class DiscoveryAttributes {
|
|||||||
"DiscoveryAttributes.GroupingAttributeType.object.displayName=Object Detected",
|
"DiscoveryAttributes.GroupingAttributeType.object.displayName=Object Detected",
|
||||||
"DiscoveryAttributes.GroupingAttributeType.mostRecentDate.displayName=Most Recent Activity Date",
|
"DiscoveryAttributes.GroupingAttributeType.mostRecentDate.displayName=Most Recent Activity Date",
|
||||||
"DiscoveryAttributes.GroupingAttributeType.firstDate.displayName=First Activity Date",
|
"DiscoveryAttributes.GroupingAttributeType.firstDate.displayName=First Activity Date",
|
||||||
"DiscoveryAttributes.GroupingAttributeType.numberOfVisits.displayName=Number of Visits",
|
"DiscoveryAttributes.GroupingAttributeType.pageViews.displayName=Page Views",
|
||||||
"DiscoveryAttributes.GroupingAttributeType.none.displayName=None",
|
"DiscoveryAttributes.GroupingAttributeType.none.displayName=None",
|
||||||
"DiscoveryAttributes.GroupingAttributeType.previouslyNotable.displayName=Previous Notability"})
|
"DiscoveryAttributes.GroupingAttributeType.previouslyNotable.displayName=Previous Notability"})
|
||||||
public enum GroupingAttributeType {
|
public enum GroupingAttributeType {
|
||||||
@ -879,7 +880,7 @@ public class DiscoveryAttributes {
|
|||||||
OBJECT_DETECTED(new ObjectDetectedAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_object_displayName()),
|
OBJECT_DETECTED(new ObjectDetectedAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_object_displayName()),
|
||||||
MOST_RECENT_DATE(new MostRecentActivityDateAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_mostRecentDate_displayName()),
|
MOST_RECENT_DATE(new MostRecentActivityDateAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_mostRecentDate_displayName()),
|
||||||
FIRST_DATE(new FirstActivityDateAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_firstDate_displayName()),
|
FIRST_DATE(new FirstActivityDateAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_firstDate_displayName()),
|
||||||
NUMBER_OF_VISITS(new NumberOfVisitsAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_numberOfVisits_displayName()),
|
PAGE_VIEWS(new PageViewsAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_pageViews_displayName()),
|
||||||
NO_GROUPING(new NoGroupingAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_none_displayName()),
|
NO_GROUPING(new NoGroupingAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_none_displayName()),
|
||||||
PREVIOUSLY_NOTABLE(new PreviouslyNotableAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_previouslyNotable_displayName());
|
PREVIOUSLY_NOTABLE(new PreviouslyNotableAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_previouslyNotable_displayName());
|
||||||
|
|
||||||
@ -928,7 +929,11 @@ public class DiscoveryAttributes {
|
|||||||
* @return Enums that can be used to group files.
|
* @return Enums that can be used to group files.
|
||||||
*/
|
*/
|
||||||
public static List<GroupingAttributeType> getOptionsForGroupingForDomains() {
|
public static List<GroupingAttributeType> getOptionsForGroupingForDomains() {
|
||||||
return Arrays.asList(FREQUENCY, MOST_RECENT_DATE, FIRST_DATE, NUMBER_OF_VISITS, PREVIOUSLY_NOTABLE);
|
if (CentralRepository.isEnabled()) {
|
||||||
|
return Arrays.asList(FREQUENCY, MOST_RECENT_DATE, FIRST_DATE, PAGE_VIEWS, PREVIOUSLY_NOTABLE);
|
||||||
|
} else {
|
||||||
|
return Arrays.asList(MOST_RECENT_DATE, FIRST_DATE, PAGE_VIEWS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1260,12 +1260,14 @@ public class DiscoveryKeyUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Key representing the number of visits.
|
* Key representing the number of page views.
|
||||||
|
* Page views are defined as the number of TSK_WEB_HISTORY artifacts that match
|
||||||
|
* a domain value.
|
||||||
*/
|
*/
|
||||||
static class NumberOfVisitsGroupKey extends GroupKey {
|
static class PageViewsGroupKey extends GroupKey {
|
||||||
|
|
||||||
private final String displayName;
|
private final String displayName;
|
||||||
private final Long visits;
|
private final Long pageViews;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new NumberOfVisitsGroupKey.
|
* Construct a new NumberOfVisitsGroupKey.
|
||||||
@ -1274,19 +1276,19 @@ public class DiscoveryKeyUtils {
|
|||||||
*/
|
*/
|
||||||
@NbBundle.Messages({
|
@NbBundle.Messages({
|
||||||
"# {0} - totalVisits",
|
"# {0} - totalVisits",
|
||||||
"DiscoveryKeyUtils.NumberOfVisitsGroupKey.displayName={0} visits",
|
"DiscoveryKeyUtils.PageViewsGroupKey.displayName={0} page views",
|
||||||
"DiscoveryKeyUtils.NumberOfVisitsGroupKey.noVisits=No visits"})
|
"DiscoveryKeyUtils.PageViewsGroupKey.noVisits=No page views"})
|
||||||
NumberOfVisitsGroupKey(Result result) {
|
PageViewsGroupKey(Result result) {
|
||||||
if (result instanceof ResultDomain) {
|
if (result instanceof ResultDomain) {
|
||||||
Long totalVisits = ((ResultDomain) result).getTotalVisits();
|
Long totalPageViews = ((ResultDomain) result).getTotalPageViews();
|
||||||
if (totalVisits == null) {
|
if (totalPageViews == null) {
|
||||||
totalVisits = 0L;
|
totalPageViews = 0L;
|
||||||
}
|
}
|
||||||
visits = totalVisits;
|
pageViews = totalPageViews;
|
||||||
displayName = Bundle.DiscoveryKeyUtils_NumberOfVisitsGroupKey_displayName(Long.toString(visits));
|
displayName = Bundle.DiscoveryKeyUtils_PageViewsGroupKey_displayName(Long.toString(pageViews));
|
||||||
} else {
|
} else {
|
||||||
displayName = Bundle.DiscoveryKeyUtils_NumberOfVisitsGroupKey_noVisits();
|
displayName = Bundle.DiscoveryKeyUtils_PageViewsGroupKey_noVisits();
|
||||||
visits = -1L;
|
pageViews = -1L;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1301,12 +1303,12 @@ public class DiscoveryKeyUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the number of visits this group is for.
|
* Get the number of page views this group is for.
|
||||||
*
|
*
|
||||||
* @return The number of visits this group is for.
|
* @return The number of page views this group is for.
|
||||||
*/
|
*/
|
||||||
Long getVisits() {
|
Long getPageViews() {
|
||||||
return visits;
|
return pageViews;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1315,19 +1317,19 @@ public class DiscoveryKeyUtils {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(otherKey instanceof NumberOfVisitsGroupKey)) {
|
if (!(otherKey instanceof PageViewsGroupKey)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
NumberOfVisitsGroupKey visitsKey = (NumberOfVisitsGroupKey) otherKey;
|
PageViewsGroupKey pageViewsKey = (PageViewsGroupKey) otherKey;
|
||||||
return visits.equals(visitsKey.getVisits());
|
return pageViews.equals(pageViewsKey.getPageViews());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(GroupKey otherGroupKey) {
|
public int compareTo(GroupKey otherGroupKey) {
|
||||||
if (otherGroupKey instanceof NumberOfVisitsGroupKey) {
|
if (otherGroupKey instanceof PageViewsGroupKey) {
|
||||||
NumberOfVisitsGroupKey visitsKey = (NumberOfVisitsGroupKey) otherGroupKey;
|
PageViewsGroupKey pageViewsKey = (PageViewsGroupKey) otherGroupKey;
|
||||||
return Long.compare(getVisits(), visitsKey.getVisits());
|
return Long.compare(getPageViews(), pageViewsKey.getPageViews());
|
||||||
} else {
|
} else {
|
||||||
return compareClassNames(otherGroupKey);
|
return compareClassNames(otherGroupKey);
|
||||||
}
|
}
|
||||||
|
@ -20,21 +20,38 @@ package org.sleuthkit.autopsy.discovery.search;
|
|||||||
|
|
||||||
import com.google.common.cache.CacheBuilder;
|
import com.google.common.cache.CacheBuilder;
|
||||||
import com.google.common.cache.LoadingCache;
|
import com.google.common.cache.LoadingCache;
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils.SearchStartedEvent;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Caches artifact requests.
|
* Caches artifact requests.
|
||||||
*/
|
*/
|
||||||
public class DomainSearchArtifactsCache {
|
public class DomainSearchArtifactsCache {
|
||||||
|
|
||||||
private static final int MAXIMUM_CACHE_SIZE = 500;
|
private static final int MAXIMUM_CACHE_SIZE = 10;
|
||||||
private static final LoadingCache<DomainSearchArtifactsRequest, List<BlackboardArtifact>> cache
|
private static final int TIME_TO_LIVE = 5; // In minutes
|
||||||
|
private static final LoadingCache<ArtifactCacheKey, Map<String, List<BlackboardArtifact>>> cache
|
||||||
= CacheBuilder.newBuilder()
|
= CacheBuilder.newBuilder()
|
||||||
.maximumSize(MAXIMUM_CACHE_SIZE)
|
.maximumSize(MAXIMUM_CACHE_SIZE)
|
||||||
|
.expireAfterWrite(TIME_TO_LIVE, TimeUnit.MINUTES)
|
||||||
.build(new DomainSearchArtifactsLoader());
|
.build(new DomainSearchArtifactsLoader());
|
||||||
|
|
||||||
|
// Listen for new search events. When this happens, we should invalidate all the
|
||||||
|
// entries in the cache. This, along with the 5 minutes expiration, ensures that
|
||||||
|
// searches get up to date results during ingest.
|
||||||
|
private static final NewSearchListener newSearchListener = new NewSearchListener();
|
||||||
|
static {
|
||||||
|
DiscoveryEventUtils.getDiscoveryEventBus().register(newSearchListener);
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Get artifact instances that match the requested criteria. If the request
|
* Get artifact instances that match the requested criteria. If the request
|
||||||
* is new, the results will be automatically loaded.
|
* is new, the results will be automatically loaded.
|
||||||
@ -53,10 +70,71 @@ public class DomainSearchArtifactsCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return cache.get(request);
|
Map<String, List<BlackboardArtifact>> artifactsByDomain = cache.get(new ArtifactCacheKey(request));
|
||||||
|
final String normalizedDomain = request.getDomain().trim().toLowerCase();
|
||||||
|
return artifactsByDomain.getOrDefault(normalizedDomain, Collections.emptyList());
|
||||||
} catch (ExecutionException ex) {
|
} catch (ExecutionException ex) {
|
||||||
//throwing a new exception with the cause so that interrupted exceptions and other causes can be checked inside our wrapper
|
//throwing a new exception with the cause so that interrupted exceptions and other causes can be checked inside our wrapper
|
||||||
throw new DiscoveryException("Error fetching artifacts from cache for " + request.toString(), ex.getCause());
|
throw new DiscoveryException("Error fetching artifacts from cache for " + request.toString(), ex.getCause());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener for new searches performed by the user.
|
||||||
|
*/
|
||||||
|
static class NewSearchListener {
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void listenToSearchStartedEvent(SearchStartedEvent event) {
|
||||||
|
cache.invalidateAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key to use for caching. Using only the artifact type and case reference
|
||||||
|
* will result in greater utilization of the cached artifact instances.
|
||||||
|
*/
|
||||||
|
class ArtifactCacheKey {
|
||||||
|
|
||||||
|
private final ARTIFACT_TYPE type;
|
||||||
|
private final SleuthkitCase caseDatabase;
|
||||||
|
|
||||||
|
private ArtifactCacheKey(DomainSearchArtifactsRequest request) {
|
||||||
|
this.type = request.getArtifactType();
|
||||||
|
this.caseDatabase = request.getSleuthkitCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
ARTIFACT_TYPE getType() {
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
SleuthkitCase getSleuthkitCase() {
|
||||||
|
return this.caseDatabase;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int hash = 7;
|
||||||
|
hash = 67 * hash + Objects.hashCode(this.type);
|
||||||
|
hash = 67 * hash + Objects.hashCode(this.caseDatabase);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj == null || getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ArtifactCacheKey other = (ArtifactCacheKey) obj;
|
||||||
|
|
||||||
|
// The artifact type and case database references must be equal.
|
||||||
|
return this.type == other.type &&
|
||||||
|
Objects.equals(this.caseDatabase, other.caseDatabase);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,46 +19,46 @@
|
|||||||
package org.sleuthkit.autopsy.discovery.search;
|
package org.sleuthkit.autopsy.discovery.search;
|
||||||
|
|
||||||
import com.google.common.cache.CacheLoader;
|
import com.google.common.cache.CacheLoader;
|
||||||
import java.util.List;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
import java.util.HashMap;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
import java.util.List;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute.Type;
|
import java.util.Map;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads artifacts for the given request. Searches TSK_DOMAIN and TSK_URL
|
* Loads artifacts for the given request. Searches for TSK domain attributes and
|
||||||
* attributes for the requested domain name. TSK_DOMAIN is exact match (ignoring
|
* organizes artifacts by those values.
|
||||||
* case). TSK_URL is sub-string match (ignoring case).
|
|
||||||
*/
|
*/
|
||||||
public class DomainSearchArtifactsLoader extends CacheLoader<DomainSearchArtifactsRequest, List<BlackboardArtifact>> {
|
public class DomainSearchArtifactsLoader extends CacheLoader<DomainSearchArtifactsCache.ArtifactCacheKey, Map<String, List<BlackboardArtifact>>> {
|
||||||
|
|
||||||
private static final Type TSK_DOMAIN = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DOMAIN);
|
private static final BlackboardAttribute.Type TSK_DOMAIN = new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN);
|
||||||
private static final Type TSK_URL = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_URL);
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<BlackboardArtifact> load(DomainSearchArtifactsRequest artifactsRequest) throws TskCoreException, InterruptedException {
|
public Map<String, List<BlackboardArtifact>> load(DomainSearchArtifactsCache.ArtifactCacheKey artifactKey) throws TskCoreException, InterruptedException {
|
||||||
final SleuthkitCase caseDb = artifactsRequest.getSleuthkitCase();
|
final SleuthkitCase caseDb = artifactKey.getSleuthkitCase();
|
||||||
final String normalizedDomain = artifactsRequest.getDomain().toLowerCase();
|
final ARTIFACT_TYPE type = artifactKey.getType();
|
||||||
final List<BlackboardArtifact> artifacts = caseDb.getBlackboardArtifacts(artifactsRequest.getArtifactType());
|
List<BlackboardArtifact> artifacts = caseDb.getBlackboardArtifacts(type);
|
||||||
final List<BlackboardArtifact> matchingDomainArtifacts = new ArrayList<>();
|
|
||||||
|
|
||||||
|
Map<String, List<BlackboardArtifact>> artifactsByDomain = new HashMap<>();
|
||||||
|
|
||||||
|
// Grab artifacts with matching domain names.
|
||||||
for (BlackboardArtifact artifact : artifacts) {
|
for (BlackboardArtifact artifact : artifacts) {
|
||||||
if(Thread.currentThread().isInterrupted()) {
|
if(Thread.currentThread().isInterrupted()) {
|
||||||
throw new InterruptedException();
|
throw new InterruptedException();
|
||||||
}
|
}
|
||||||
final BlackboardAttribute tskDomain = artifact.getAttribute(TSK_DOMAIN);
|
final BlackboardAttribute tskDomain = artifact.getAttribute(TSK_DOMAIN);
|
||||||
final BlackboardAttribute tskUrl = artifact.getAttribute(TSK_URL);
|
if (tskDomain != null) {
|
||||||
|
final String normalizedDomain = tskDomain.getValueString().trim().toLowerCase();
|
||||||
if (tskDomain != null && tskDomain.getValueString().equalsIgnoreCase(normalizedDomain)) {
|
List<BlackboardArtifact> artifactsWithDomain = artifactsByDomain.getOrDefault(normalizedDomain, new ArrayList<>());
|
||||||
matchingDomainArtifacts.add(artifact);
|
artifactsWithDomain.add(artifact);
|
||||||
} else if (tskUrl != null && tskUrl.getValueString().toLowerCase().contains(normalizedDomain)) {
|
artifactsByDomain.put(normalizedDomain, artifactsWithDomain);
|
||||||
matchingDomainArtifacts.add(artifact);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return matchingDomainArtifacts;
|
return artifactsByDomain;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,12 +154,12 @@ class DomainSearchCacheLoader extends CacheLoader<SearchKey, Map<GroupKey, List<
|
|||||||
+ " SUM(CASE "
|
+ " SUM(CASE "
|
||||||
+ " WHEN artifact_type_id = " + TSK_WEB_HISTORY.getTypeID() + " THEN 1 "
|
+ " WHEN artifact_type_id = " + TSK_WEB_HISTORY.getTypeID() + " THEN 1 "
|
||||||
+ " ELSE 0 "
|
+ " ELSE 0 "
|
||||||
+ " END) AS totalVisits,"
|
+ " END) AS totalPageViews,"
|
||||||
+ " SUM(CASE "
|
+ " SUM(CASE "
|
||||||
+ " WHEN artifact_type_id = " + TSK_WEB_HISTORY.getTypeID() + " AND"
|
+ " WHEN artifact_type_id = " + TSK_WEB_HISTORY.getTypeID() + " AND"
|
||||||
+ " date BETWEEN " + sixtyDaysAgo.getEpochSecond() + " AND " + currentTime.getEpochSecond() + " THEN 1 "
|
+ " date BETWEEN " + sixtyDaysAgo.getEpochSecond() + " AND " + currentTime.getEpochSecond() + " THEN 1 "
|
||||||
+ " ELSE 0 "
|
+ " ELSE 0 "
|
||||||
+ " END) AS last60,"
|
+ " END) AS pageViewsInLast60,"
|
||||||
+ " MAX(data_source_obj_id) AS dataSource "
|
+ " MAX(data_source_obj_id) AS dataSource "
|
||||||
+ "FROM blackboard_artifacts"
|
+ "FROM blackboard_artifacts"
|
||||||
+ " JOIN (" + domainsTable + ") AS domains_table"
|
+ " JOIN (" + domainsTable + ") AS domains_table"
|
||||||
@ -298,21 +298,21 @@ class DomainSearchCacheLoader extends CacheLoader<SearchKey, Map<GroupKey, List<
|
|||||||
if (resultSet.wasNull()) {
|
if (resultSet.wasNull()) {
|
||||||
filesDownloaded = null;
|
filesDownloaded = null;
|
||||||
}
|
}
|
||||||
Long totalVisits = resultSet.getLong("totalVisits");
|
Long totalPageViews = resultSet.getLong("totalPageViews");
|
||||||
if (resultSet.wasNull()) {
|
if (resultSet.wasNull()) {
|
||||||
totalVisits = null;
|
totalPageViews = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Long visitsInLast60 = resultSet.getLong("last60");
|
Long pageViewsInLast60 = resultSet.getLong("pageViewsInLast60");
|
||||||
if (resultSet.wasNull()) {
|
if (resultSet.wasNull()) {
|
||||||
visitsInLast60 = null;
|
pageViewsInLast60 = null;
|
||||||
}
|
}
|
||||||
Long dataSourceID = resultSet.getLong("dataSource");
|
Long dataSourceID = resultSet.getLong("dataSource");
|
||||||
|
|
||||||
Content dataSource = skc.getContentById(dataSourceID);
|
Content dataSource = skc.getContentById(dataSourceID);
|
||||||
|
|
||||||
resultDomains.add(new ResultDomain(domain, activityStart,
|
resultDomains.add(new ResultDomain(domain, activityStart,
|
||||||
activityEnd, totalVisits, visitsInLast60, filesDownloaded, dataSource));
|
activityEnd, totalPageViews, pageViewsInLast60, filesDownloaded, dataSource));
|
||||||
}
|
}
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
this.sqlCause = ex;
|
this.sqlCause = ex;
|
||||||
|
@ -30,8 +30,8 @@ public class ResultDomain extends Result {
|
|||||||
private final String domain;
|
private final String domain;
|
||||||
private final Long activityStart;
|
private final Long activityStart;
|
||||||
private final Long activityEnd;
|
private final Long activityEnd;
|
||||||
private final Long totalVisits;
|
private final Long totalPageViews;
|
||||||
private final Long visitsInLast60;
|
private final Long pageViewsInLast60;
|
||||||
private final Long filesDownloaded;
|
private final Long filesDownloaded;
|
||||||
|
|
||||||
private final Content dataSource;
|
private final Content dataSource;
|
||||||
@ -42,15 +42,15 @@ public class ResultDomain extends Result {
|
|||||||
*
|
*
|
||||||
* @param domain The domain the result is being created from.
|
* @param domain The domain the result is being created from.
|
||||||
*/
|
*/
|
||||||
ResultDomain(String domain, Long activityStart, Long activityEnd, Long totalVisits,
|
ResultDomain(String domain, Long activityStart, Long activityEnd, Long totalPageViews,
|
||||||
Long visitsInLast60, Long filesDownloaded, Content dataSource) {
|
Long pageViewsInLast60, Long filesDownloaded, Content dataSource) {
|
||||||
this.domain = domain;
|
this.domain = domain;
|
||||||
this.dataSource = dataSource;
|
this.dataSource = dataSource;
|
||||||
this.dataSourceId = dataSource.getId();
|
this.dataSourceId = dataSource.getId();
|
||||||
this.activityStart = activityStart;
|
this.activityStart = activityStart;
|
||||||
this.activityEnd = activityEnd;
|
this.activityEnd = activityEnd;
|
||||||
this.totalVisits = totalVisits;
|
this.totalPageViews = totalPageViews;
|
||||||
this.visitsInLast60 = visitsInLast60;
|
this.pageViewsInLast60 = pageViewsInLast60;
|
||||||
this.filesDownloaded = filesDownloaded;
|
this.filesDownloaded = filesDownloaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,22 +82,24 @@ public class ResultDomain extends Result {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the total number of visits that this domain has had.
|
* Get the total number of page views that this domain has had.
|
||||||
|
* Pages views is defined as the count of TSK_WEB_HISTORY artifacts.
|
||||||
*
|
*
|
||||||
* @return The total number of visits that this domain has had.
|
* @return The total number of page views that this domain has had.
|
||||||
*/
|
*/
|
||||||
public Long getTotalVisits() {
|
public Long getTotalPageViews() {
|
||||||
return totalVisits;
|
return totalPageViews;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the number of visits that this domain has had in the last 60 days.
|
* Get the number of page views that this domain has had in the last 60 days.
|
||||||
|
* Page views is defined as the count of TSK_WEB_HISTORY artifacts.
|
||||||
*
|
*
|
||||||
* @return The number of visits that this domain has had in the last 60
|
* @return The number of page views that this domain has had in the last 60
|
||||||
* days.
|
* days.
|
||||||
*/
|
*/
|
||||||
public Long getVisitsInLast60() {
|
public Long getPageViewsInLast60Days() {
|
||||||
return visitsInLast60;
|
return pageViewsInLast60;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -132,8 +134,8 @@ public class ResultDomain extends Result {
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "[domain=" + this.domain + ", data_source=" + this.dataSourceId + ", start="
|
return "[domain=" + this.domain + ", data_source=" + this.dataSourceId + ", start="
|
||||||
+ this.activityStart + ", end=" + this.activityEnd + ", totalVisits=" + this.totalVisits + ", visitsLast60="
|
+ this.activityStart + ", end=" + this.activityEnd + ", totalVisits=" + this.totalPageViews + ", visitsLast60="
|
||||||
+ this.visitsInLast60 + ", downloads=" + this.filesDownloaded + ", frequency="
|
+ this.pageViewsInLast60 + ", downloads=" + this.filesDownloaded + ", frequency="
|
||||||
+ this.getFrequency() + "]";
|
+ this.getFrequency() + "]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,9 @@ public class ResultsSorter implements Comparator<Result> {
|
|||||||
case BY_DOMAIN_NAME:
|
case BY_DOMAIN_NAME:
|
||||||
comparators.add(getDomainNameComparator());
|
comparators.add(getDomainNameComparator());
|
||||||
break;
|
break;
|
||||||
|
case BY_PAGE_VIEWS:
|
||||||
|
comparators.add(getPageViewComparator());
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
// The default comparator will be added afterward
|
// The default comparator will be added afterward
|
||||||
break;
|
break;
|
||||||
@ -250,19 +253,29 @@ public class ResultsSorter implements Comparator<Result> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sorts results by most recent date time.
|
* Sorts domains by page view count. If a result domain reports it's
|
||||||
|
* page view count as `null`, then it's assumed to be equivalent to 0.
|
||||||
*
|
*
|
||||||
* @return -1 if domain1 comes before domain2, 0 if equal, 1 otherwise.
|
* This comparator sorts results in descending order (largest -> smallest).
|
||||||
*/
|
*/
|
||||||
private static Comparator<Result> getMostRecentDateTimeComparator() {
|
private static Comparator<Result> getPageViewComparator() {
|
||||||
return (Result result1, Result result2) -> {
|
return (Result domain1, Result domain2) -> {
|
||||||
if (result1.getType() != SearchData.Type.DOMAIN) {
|
if (domain1.getType() != SearchData.Type.DOMAIN) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultDomain first = (ResultDomain) result1;
|
ResultDomain first = (ResultDomain) domain1;
|
||||||
ResultDomain second = (ResultDomain) result2;
|
ResultDomain second = (ResultDomain) domain2;
|
||||||
return Long.compare(second.getActivityEnd(), first.getActivityEnd());
|
|
||||||
|
Long firstPageViews = first.getTotalPageViews();
|
||||||
|
Long secondPageViews = second.getTotalPageViews();
|
||||||
|
if (firstPageViews != null && secondPageViews != null) {
|
||||||
|
return Long.compare(secondPageViews, firstPageViews);
|
||||||
|
} else if (firstPageViews == null) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,7 +331,8 @@ public class ResultsSorter implements Comparator<Result> {
|
|||||||
"FileSorter.SortingMethod.frequency.displayName=Central Repo Frequency",
|
"FileSorter.SortingMethod.frequency.displayName=Central Repo Frequency",
|
||||||
"FileSorter.SortingMethod.keywordlist.displayName=Keyword List Names",
|
"FileSorter.SortingMethod.keywordlist.displayName=Keyword List Names",
|
||||||
"FileSorter.SortingMethod.fullPath.displayName=Full Path",
|
"FileSorter.SortingMethod.fullPath.displayName=Full Path",
|
||||||
"FileSorter.SortingMethod.domain.displayName=Domain"})
|
"FileSorter.SortingMethod.domain.displayName=Domain",
|
||||||
|
"FileSorter.SortingMethod.pageViews.displayName=Page Views"})
|
||||||
public enum SortingMethod {
|
public enum SortingMethod {
|
||||||
BY_FILE_NAME(new ArrayList<>(),
|
BY_FILE_NAME(new ArrayList<>(),
|
||||||
Bundle.FileSorter_SortingMethod_filename_displayName()), // Sort alphabetically by file name
|
Bundle.FileSorter_SortingMethod_filename_displayName()), // Sort alphabetically by file name
|
||||||
@ -335,7 +349,8 @@ public class ResultsSorter implements Comparator<Result> {
|
|||||||
BY_FULL_PATH(new ArrayList<>(),
|
BY_FULL_PATH(new ArrayList<>(),
|
||||||
Bundle.FileSorter_SortingMethod_fullPath_displayName()), // Sort alphabetically by path
|
Bundle.FileSorter_SortingMethod_fullPath_displayName()), // Sort alphabetically by path
|
||||||
BY_DOMAIN_NAME(new ArrayList<>(),
|
BY_DOMAIN_NAME(new ArrayList<>(),
|
||||||
Bundle.FileSorter_SortingMethod_domain_displayName());
|
Bundle.FileSorter_SortingMethod_domain_displayName()),
|
||||||
|
BY_PAGE_VIEWS(new ArrayList<>(), Bundle.FileSorter_SortingMethod_pageViews_displayName());
|
||||||
|
|
||||||
private final String displayName;
|
private final String displayName;
|
||||||
private final List<DiscoveryAttributes.AttributeType> requiredAttributes;
|
private final List<DiscoveryAttributes.AttributeType> requiredAttributes;
|
||||||
@ -381,7 +396,7 @@ public class ResultsSorter implements Comparator<Result> {
|
|||||||
* @return Enum values that can be used to ordering files.
|
* @return Enum values that can be used to ordering files.
|
||||||
*/
|
*/
|
||||||
public static List<SortingMethod> getOptionsForOrderingDomains() {
|
public static List<SortingMethod> getOptionsForOrderingDomains() {
|
||||||
return Arrays.asList(BY_DOMAIN_NAME, BY_DATA_SOURCE);
|
return Arrays.asList(BY_PAGE_VIEWS, BY_DOMAIN_NAME, BY_DATA_SOURCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -31,8 +31,10 @@ import org.openide.util.NbBundle;
|
|||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
|
import org.sleuthkit.datamodel.TimeUtilities;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -238,10 +240,11 @@ final class ArtifactsListPanel extends AbstractArtifactListPanel {
|
|||||||
@Override
|
@Override
|
||||||
public Object getValueAt(int rowIndex, int columnIndex) {
|
public Object getValueAt(int rowIndex, int columnIndex) {
|
||||||
if (columnIndex < 2 || artifactType == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CACHE) {
|
if (columnIndex < 2 || artifactType == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CACHE) {
|
||||||
|
final BlackboardArtifact artifact = getArtifactByRow(rowIndex);
|
||||||
try {
|
try {
|
||||||
for (BlackboardAttribute bba : getArtifactByRow(rowIndex).getAttributes()) {
|
for (BlackboardAttribute bba : artifact.getAttributes()) {
|
||||||
if (!StringUtils.isBlank(bba.getDisplayString())) {
|
if (!StringUtils.isBlank(bba.getDisplayString())) {
|
||||||
String stringFromAttribute = getStringForColumn(bba, columnIndex);
|
String stringFromAttribute = getStringForColumn(artifact, bba, columnIndex);
|
||||||
if (!StringUtils.isBlank(stringFromAttribute)) {
|
if (!StringUtils.isBlank(stringFromAttribute)) {
|
||||||
return stringFromAttribute;
|
return stringFromAttribute;
|
||||||
}
|
}
|
||||||
@ -249,7 +252,7 @@ final class ArtifactsListPanel extends AbstractArtifactListPanel {
|
|||||||
}
|
}
|
||||||
return getFallbackValue(rowIndex, columnIndex);
|
return getFallbackValue(rowIndex, columnIndex);
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
logger.log(Level.WARNING, "Error getting attributes for artifact " + getArtifactByRow(rowIndex).getArtifactID(), ex);
|
logger.log(Level.WARNING, "Error getting attributes for artifact " + artifact.getArtifactID(), ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Bundle.ArtifactsListPanel_value_noValue();
|
return Bundle.ArtifactsListPanel_value_noValue();
|
||||||
@ -270,9 +273,9 @@ final class ArtifactsListPanel extends AbstractArtifactListPanel {
|
|||||||
* the TSK_PATH_ID.
|
* the TSK_PATH_ID.
|
||||||
*/
|
*/
|
||||||
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||||
private String getStringForColumn(BlackboardAttribute bba, int columnIndex) throws TskCoreException {
|
private String getStringForColumn(BlackboardArtifact artifact, BlackboardAttribute bba, int columnIndex) throws TskCoreException {
|
||||||
if (columnIndex == 0 && bba.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID()) {
|
if (columnIndex == 0 && bba.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID()) {
|
||||||
return bba.getDisplayString();
|
return TimeUtilities.epochToTime(bba.getValueLong(), ContentUtils.getTimeZone(artifact));
|
||||||
} else if (columnIndex == 1) {
|
} else if (columnIndex == 1) {
|
||||||
if (artifactType == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD || artifactType == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CACHE) {
|
if (artifactType == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD || artifactType == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CACHE) {
|
||||||
if (bba.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID.getTypeID()) {
|
if (bba.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID.getTypeID()) {
|
||||||
@ -305,9 +308,10 @@ final class ArtifactsListPanel extends AbstractArtifactListPanel {
|
|||||||
*/
|
*/
|
||||||
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||||
private String getFallbackValue(int rowIndex, int columnIndex) throws TskCoreException {
|
private String getFallbackValue(int rowIndex, int columnIndex) throws TskCoreException {
|
||||||
for (BlackboardAttribute bba : getArtifactByRow(rowIndex).getAttributes()) {
|
final BlackboardArtifact artifact = getArtifactByRow(rowIndex);
|
||||||
|
for (BlackboardAttribute bba : artifact.getAttributes()) {
|
||||||
if (columnIndex == 0 && bba.getAttributeType().getTypeName().startsWith("TSK_DATETIME") && !StringUtils.isBlank(bba.getDisplayString())) {
|
if (columnIndex == 0 && bba.getAttributeType().getTypeName().startsWith("TSK_DATETIME") && !StringUtils.isBlank(bba.getDisplayString())) {
|
||||||
return bba.getDisplayString();
|
return TimeUtilities.epochToTime(bba.getValueLong(), ContentUtils.getTimeZone(artifact));
|
||||||
} else if (columnIndex == 1 && bba.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL.getTypeID() && !StringUtils.isBlank(bba.getDisplayString())) {
|
} else if (columnIndex == 1 && bba.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL.getTypeID() && !StringUtils.isBlank(bba.getDisplayString())) {
|
||||||
return bba.getDisplayString();
|
return bba.getDisplayString();
|
||||||
} else if (columnIndex == 1 && bba.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME.getTypeID() && !StringUtils.isBlank(bba.getDisplayString())) {
|
} else if (columnIndex == 1 && bba.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME.getTypeID() && !StringUtils.isBlank(bba.getDisplayString())) {
|
||||||
|
@ -56,8 +56,8 @@ DomainDetailsPanel.miniTimelineTitle.text=Mini Timeline
|
|||||||
DomainSummaryPanel.activity.text=Activity: {0} to {1}
|
DomainSummaryPanel.activity.text=Activity: {0} to {1}
|
||||||
DomainSummaryPanel.downloads.text=Files downloaded:
|
DomainSummaryPanel.downloads.text=Files downloaded:
|
||||||
DomainSummaryPanel.loadingImages.text=Loading thumbnail...
|
DomainSummaryPanel.loadingImages.text=Loading thumbnail...
|
||||||
DomainSummaryPanel.pages.text=Pages in past 60 days:
|
DomainSummaryPanel.pages.text=Page views in past 60 days:
|
||||||
DomainSummaryPanel.totalPages.text=Total visits:
|
DomainSummaryPanel.totalPages.text=Total page views:
|
||||||
GroupsListPanel.noDomainResults.message.text=No domains were found for the selected filters.\n\nReminder:\n -The Recent Activity module must be run on each data source you want to find results in.\n -The Central Repository module must be run on each data source if you want to filter or sort by past occurrences.\n -The iOS Analyzer (iLEAPP) module must be run on each data source which contains data from an iOS device.\n
|
GroupsListPanel.noDomainResults.message.text=No domains were found for the selected filters.\n\nReminder:\n -The Recent Activity module must be run on each data source you want to find results in.\n -The Central Repository module must be run on each data source if you want to filter or sort by past occurrences.\n -The iOS Analyzer (iLEAPP) module must be run on each data source which contains data from an iOS device.\n
|
||||||
GroupsListPanel.noFileResults.message.text=No files were found for the selected filters.\n\nReminder:\n -The File Type Identification module must be run on each data source you want to find results in.\n -The Hash Lookup module must be run on each data source if you want to filter by past occurrence.\n -The Picture Analyzer module must be run on each data source if you are filtering by User Created content.
|
GroupsListPanel.noFileResults.message.text=No files were found for the selected filters.\n\nReminder:\n -The File Type Identification module must be run on each data source you want to find results in.\n -The Hash Lookup module must be run on each data source if you want to filter by past occurrence.\n -The Picture Analyzer module must be run on each data source if you are filtering by User Created content.
|
||||||
GroupsListPanel.noResults.title.text=No results found
|
GroupsListPanel.noResults.title.text=No results found
|
||||||
|
@ -142,8 +142,8 @@ class DomainSummaryPanel extends javax.swing.JPanel implements ListCellRenderer<
|
|||||||
@NbBundle.Messages({"# {0} - startDate",
|
@NbBundle.Messages({"# {0} - startDate",
|
||||||
"# {1} - endDate",
|
"# {1} - endDate",
|
||||||
"DomainSummaryPanel.activity.text=Activity: {0} to {1}",
|
"DomainSummaryPanel.activity.text=Activity: {0} to {1}",
|
||||||
"DomainSummaryPanel.pages.text=Pages in past 60 days: ",
|
"DomainSummaryPanel.pages.text=Page views in past 60 days: ",
|
||||||
"DomainSummaryPanel.totalPages.text=Total visits: ",
|
"DomainSummaryPanel.totalPages.text=Total page views: ",
|
||||||
"DomainSummaryPanel.downloads.text=Files downloaded: ",
|
"DomainSummaryPanel.downloads.text=Files downloaded: ",
|
||||||
"DomainSummaryPanel.loadingImages.text=Loading thumbnail..."})
|
"DomainSummaryPanel.loadingImages.text=Loading thumbnail..."})
|
||||||
@Override
|
@Override
|
||||||
@ -152,8 +152,8 @@ class DomainSummaryPanel extends javax.swing.JPanel implements ListCellRenderer<
|
|||||||
String startDate = dateFormat.format(new Date(value.getResultDomain().getActivityStart() * 1000));
|
String startDate = dateFormat.format(new Date(value.getResultDomain().getActivityStart() * 1000));
|
||||||
String endDate = dateFormat.format(new Date(value.getResultDomain().getActivityEnd() * 1000));
|
String endDate = dateFormat.format(new Date(value.getResultDomain().getActivityEnd() * 1000));
|
||||||
activityLabel.setText(Bundle.DomainSummaryPanel_activity_text(startDate, endDate));
|
activityLabel.setText(Bundle.DomainSummaryPanel_activity_text(startDate, endDate));
|
||||||
totalVisitsLabel.setText(Bundle.DomainSummaryPanel_totalPages_text() + value.getResultDomain().getTotalVisits());
|
totalVisitsLabel.setText(Bundle.DomainSummaryPanel_totalPages_text() + value.getResultDomain().getTotalPageViews());
|
||||||
pagesLabel.setText(Bundle.DomainSummaryPanel_pages_text() + value.getResultDomain().getVisitsInLast60());
|
pagesLabel.setText(Bundle.DomainSummaryPanel_pages_text() + value.getResultDomain().getPageViewsInLast60Days());
|
||||||
filesDownloadedLabel.setText(Bundle.DomainSummaryPanel_downloads_text() + value.getResultDomain().getFilesDownloaded());
|
filesDownloadedLabel.setText(Bundle.DomainSummaryPanel_downloads_text() + value.getResultDomain().getFilesDownloaded());
|
||||||
if (value.getThumbnail() == null) {
|
if (value.getThumbnail() == null) {
|
||||||
numberOfImagesLabel.setText(Bundle.DomainSummaryPanel_loadingImages_text());
|
numberOfImagesLabel.setText(Bundle.DomainSummaryPanel_loadingImages_text());
|
||||||
|
@ -22,6 +22,7 @@ import org.sleuthkit.autopsy.discovery.search.AbstractFilter;
|
|||||||
import javax.swing.JCheckBox;
|
import javax.swing.JCheckBox;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.JList;
|
import javax.swing.JList;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
|
||||||
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
||||||
import org.sleuthkit.autopsy.discovery.search.SearchFiltering;
|
import org.sleuthkit.autopsy.discovery.search.SearchFiltering;
|
||||||
|
|
||||||
@ -35,6 +36,9 @@ final class PreviouslyNotableFilterPanel extends AbstractDiscoveryFilterPanel {
|
|||||||
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||||
PreviouslyNotableFilterPanel() {
|
PreviouslyNotableFilterPanel() {
|
||||||
initComponents();
|
initComponents();
|
||||||
|
if (!CentralRepository.isEnabled()) {
|
||||||
|
previouslyNotableCheckbox.setEnabled(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user