Implemented the DoD, tested and commented the code

This commit is contained in:
U-BASIS\dsmyda 2020-12-16 17:38:47 -05:00
parent 37e4dce789
commit 477d8c6d72
10 changed files with 195 additions and 108 deletions

View File

@ -1,3 +1,7 @@
# {0} - month abbreviation
# {1} - day of month
# {2} - year
DiscoveryAttributes.ActivityDateGroupKey.getDisplayNameTemplate=Week of {0} {1}, {2}
DiscoveryAttributes.GroupingAttributeType.datasource.displayName=Data Source DiscoveryAttributes.GroupingAttributeType.datasource.displayName=Data Source
DiscoveryAttributes.GroupingAttributeType.fileType.displayName=File Type DiscoveryAttributes.GroupingAttributeType.fileType.displayName=File Type
DiscoveryAttributes.GroupingAttributeType.firstDate.displayName=First Activity Date DiscoveryAttributes.GroupingAttributeType.firstDate.displayName=First Activity Date
@ -20,11 +24,9 @@ DiscoveryKeyUtils.DataSourceGroupKey.datasourceAndID={0}(ID: {1})
# {0} - Data source ID # {0} - Data source ID
DiscoveryKeyUtils.DataSourceGroupKey.idOnly=Data source (ID: {0}) DiscoveryKeyUtils.DataSourceGroupKey.idOnly=Data source (ID: {0})
DiscoveryKeyUtils.FileTagGroupKey.noSets=None DiscoveryKeyUtils.FileTagGroupKey.noSets=None
DiscoveryKeyUtils.FirstActivityDateGroupKey.noDate=No Date Available
DiscoveryKeyUtils.HashHitsGroupKey.noHashHits=None DiscoveryKeyUtils.HashHitsGroupKey.noHashHits=None
DiscoveryKeyUtils.InterestingItemGroupKey.noSets=None DiscoveryKeyUtils.InterestingItemGroupKey.noSets=None
DiscoveryKeyUtils.KeywordListGroupKey.noKeywords=None DiscoveryKeyUtils.KeywordListGroupKey.noKeywords=None
DiscoveryKeyUtils.LastActivityDateGroupKey.noDate=No Date Available
DiscoveryKeyUtils.NoGroupingGroupKey.allFiles=All Files DiscoveryKeyUtils.NoGroupingGroupKey.allFiles=All Files
DiscoveryKeyUtils.ObjectDetectedGroupKey.noSets=None DiscoveryKeyUtils.ObjectDetectedGroupKey.noSets=None
# {0} - domain # {0} - domain

View File

@ -18,18 +18,21 @@
*/ */
package org.sleuthkit.autopsy.discovery.search; package org.sleuthkit.autopsy.discovery.search;
import java.text.SimpleDateFormat; import java.time.DayOfWeek;
import java.time.Instant;
import java.time.ZonedDateTime;
import java.time.temporal.TemporalAdjusters;
import java.util.Collections; import java.util.Collections;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.TimeUnit; import java.util.TimeZone;
import java.util.logging.Level; import java.util.logging.Level;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.discovery.search.SearchData.PageViews; import org.sleuthkit.autopsy.discovery.search.SearchData.PageViews;
import org.sleuthkit.autopsy.discovery.ui.MonthAbbreviation;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
@ -1134,29 +1137,34 @@ public class DiscoveryKeyUtils {
*/ */
static class LastActivityDateGroupKey extends GroupKey { static class LastActivityDateGroupKey extends GroupKey {
private final Long epochDate; private ZonedDateTime currentWeekCutOff;
private final String dateNameString;
/** /**
* Construct a new LastActivityDateGroupKey. * Construct a new LastActivityDateGroupKey.
* *
* @param result The Result to create the group key for. * @param result The Result to create the group key for.
*/ */
@NbBundle.Messages({
"DiscoveryKeyUtils.LastActivityDateGroupKey.noDate=No Date Available"})
LastActivityDateGroupKey(Result result) { LastActivityDateGroupKey(Result result) {
if (result instanceof ResultDomain) { if (result instanceof ResultDomain) {
epochDate = ((ResultDomain) result).getActivityEnd(); ResultDomain domainResult = ((ResultDomain) result);
dateNameString = new SimpleDateFormat("yyyy/MM/dd", Locale.getDefault()).format(new Date(TimeUnit.SECONDS.toMillis(epochDate))); currentWeekCutOff = getCurrentWeekCutOff(domainResult.getActivityEnd(), domainResult);
} else { } else {
epochDate = Long.MAX_VALUE; throw new IllegalArgumentException("Expected a domain result only.");
dateNameString = Bundle.DiscoveryKeyUtils_LastActivityDateGroupKey_noDate();
} }
} }
@NbBundle.Messages({
"# {0} - month abbreviation",
"# {1} - day of month",
"# {2} - year",
"DiscoveryAttributes.ActivityDateGroupKey.getDisplayNameTemplate=Week of {0} {1}, {2}"
})
@Override @Override
String getDisplayName() { String getDisplayName() {
return getDateNameString(); MonthAbbreviation currentCutOffMonth = MonthAbbreviation.fromMonthValue(currentWeekCutOff.getMonthValue());
return Bundle.DiscoveryAttributes_ActivityDateGroupKey_getDisplayNameTemplate(
currentCutOffMonth.toString(), Integer.toString(currentWeekCutOff.getDayOfMonth()),
Integer.toString(currentWeekCutOff.getYear()));
} }
@Override @Override
@ -1170,53 +1178,40 @@ public class DiscoveryKeyUtils {
} }
LastActivityDateGroupKey dateGroupKey = (LastActivityDateGroupKey) otherKey; LastActivityDateGroupKey dateGroupKey = (LastActivityDateGroupKey) otherKey;
return getDateNameString().equals(dateGroupKey.getDateNameString()); return getDisplayName().equals(dateGroupKey.getDisplayName());
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(getDateNameString()); return Objects.hash(getDisplayName());
} }
@Override @Override
public int compareTo(GroupKey otherGroupKey) { public int compareTo(GroupKey otherGroupKey) {
if (otherGroupKey instanceof LastActivityDateGroupKey) { if (otherGroupKey instanceof LastActivityDateGroupKey) {
LastActivityDateGroupKey otherDateGroupKey = (LastActivityDateGroupKey) otherGroupKey; LastActivityDateGroupKey otherDateGroupKey = (LastActivityDateGroupKey) otherGroupKey;
return Long.compare(otherDateGroupKey.currentWeekCutOff.toEpochSecond(), currentWeekCutOff.toEpochSecond());
// Put the empty list at the end
if (this.getEpochDate().equals(Long.MAX_VALUE)) {
if (otherDateGroupKey.getEpochDate().equals(Long.MAX_VALUE)) {
return 0;
} else {
return 1;
}
} else if (otherDateGroupKey.getEpochDate().equals(Long.MAX_VALUE)) {
return -1;
}
return getDateNameString().compareTo(otherDateGroupKey.getDateNameString());
} else { } else {
return compareClassNames(otherGroupKey); return compareClassNames(otherGroupKey);
} }
} }
}
/** /**
* Get the date this group is for as a Long. * Get the next closed Sunday given an epoch time and timezone.
* * Dates for grouping are managed on a weekly basis. Each Sunday
* @return The date. * acts as the boundary and representative for the week.
*/ */
Long getEpochDate() { private static ZonedDateTime getCurrentWeekCutOff(long epochSeconds, ResultDomain domainResult) {
return epochDate; Instant startActivityAsInsant = Instant.ofEpochSecond(epochSeconds);
} // Determines the timezone using the settings panel or value parsed from the
// parent data source
/** TimeZone currentTimeZone = ContentUtils.getTimeZone(domainResult.getDataSource());
* Get the name which identifies this group. // Convert to a datetime using epoch and timezone.
* ZonedDateTime startActivityAsDateTime = ZonedDateTime.ofInstant(startActivityAsInsant, currentTimeZone.toZoneId());
* @return The dateNameString. // Get the closest Sunday, which is the cut off for the current week.
*/ // Use this cut off to perform grouping and comparing.
String getDateNameString() { return startActivityAsDateTime.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
return dateNameString;
}
} }
/** /**
@ -1224,29 +1219,28 @@ public class DiscoveryKeyUtils {
*/ */
static class FirstActivityDateGroupKey extends GroupKey { static class FirstActivityDateGroupKey extends GroupKey {
private final Long epochDate; private ZonedDateTime currentWeekCutOff;
private final String dateNameString;
/** /**
* Construct a new FirstActivityDateGroupKey. * Construct a new FirstActivityDateGroupKey.
* *
* @param result The Result to create the group key for. * @param result The Result to create the group key for.
*/ */
@NbBundle.Messages({
"DiscoveryKeyUtils.FirstActivityDateGroupKey.noDate=No Date Available"})
FirstActivityDateGroupKey(Result result) { FirstActivityDateGroupKey(Result result) {
if (result instanceof ResultDomain) { if (result instanceof ResultDomain) {
epochDate = ((ResultDomain) result).getActivityStart(); ResultDomain domainResult = ((ResultDomain) result);
dateNameString = new SimpleDateFormat("yyyy/MM/dd", Locale.getDefault()).format(new Date(TimeUnit.SECONDS.toMillis(epochDate))); currentWeekCutOff = getCurrentWeekCutOff(domainResult.getActivityStart(), domainResult);
} else { } else {
epochDate = Long.MAX_VALUE; throw new IllegalArgumentException("Expected a domain result only.");
dateNameString = Bundle.DiscoveryKeyUtils_FirstActivityDateGroupKey_noDate();
} }
} }
@Override @Override
String getDisplayName() { String getDisplayName() {
return getDateNameString(); MonthAbbreviation currentCutOffMonth = MonthAbbreviation.fromMonthValue(currentWeekCutOff.getMonthValue());
return Bundle.DiscoveryAttributes_ActivityDateGroupKey_getDisplayNameTemplate(
currentCutOffMonth.toString(), Integer.toString(currentWeekCutOff.getDayOfMonth()),
Integer.toString(currentWeekCutOff.getYear()));
} }
@Override @Override
@ -1260,53 +1254,23 @@ public class DiscoveryKeyUtils {
} }
FirstActivityDateGroupKey dateGroupKey = (FirstActivityDateGroupKey) otherKey; FirstActivityDateGroupKey dateGroupKey = (FirstActivityDateGroupKey) otherKey;
return getDateNameString().equals(dateGroupKey.getDateNameString()); return getDisplayName().equals(dateGroupKey.getDisplayName());
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(getDateNameString()); return Objects.hash(getDisplayName());
} }
@Override @Override
public int compareTo(GroupKey otherGroupKey) { public int compareTo(GroupKey otherGroupKey) {
if (otherGroupKey instanceof FirstActivityDateGroupKey) { if (otherGroupKey instanceof FirstActivityDateGroupKey) {
FirstActivityDateGroupKey otherDateGroupKey = (FirstActivityDateGroupKey) otherGroupKey; FirstActivityDateGroupKey otherDateGroupKey = (FirstActivityDateGroupKey) otherGroupKey;
return Long.compare(otherDateGroupKey.currentWeekCutOff.toEpochSecond(), currentWeekCutOff.toEpochSecond());
// Put the empty list at the end
if (this.getEpochDate().equals(Long.MAX_VALUE)) {
if (otherDateGroupKey.getEpochDate().equals(Long.MAX_VALUE)) {
return 0;
} else {
return 1;
}
} else if (otherDateGroupKey.getEpochDate().equals(Long.MAX_VALUE)) {
return -1;
}
return getDateNameString().compareTo(otherDateGroupKey.getDateNameString());
} else { } else {
return compareClassNames(otherGroupKey); return compareClassNames(otherGroupKey);
} }
} }
/**
* Get the date this group is for as a Long.
*
* @return The date.
*/
Long getEpochDate() {
return epochDate;
}
/**
* Get the name which identifies this group.
*
* @return The dateNameString.
*/
String getDateNameString() {
return dateNameString;
}
} }
/** /**

View File

@ -24,12 +24,15 @@ import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TimeZone;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TimeUtilities;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
/** /**
@ -245,7 +248,8 @@ public class DomainSearch {
private String getDate(BlackboardArtifact artifact) throws TskCoreException { private String getDate(BlackboardArtifact artifact) throws TskCoreException {
for (BlackboardAttribute attribute : artifact.getAttributes()) { for (BlackboardAttribute attribute : artifact.getAttributes()) {
if (attribute.getAttributeType().getTypeName().startsWith("TSK_DATETIME")) { if (attribute.getAttributeType().getTypeName().startsWith("TSK_DATETIME")) {
String dateString = attribute.getDisplayString(); TimeZone timeZone = ContentUtils.getTimeZone(artifact);
String dateString = TimeUtilities.epochToTime(attribute.getValueLong(), timeZone);
if (dateString.length() >= 10) { if (dateString.length() >= 10) {
return dateString.substring(0, 10); return dateString.substring(0, 10);
} }

View File

@ -212,13 +212,14 @@ class DomainSearchCacheLoader extends CacheLoader<SearchKey, Map<GroupKey, List<
final StringJoiner whereClause = new StringJoiner(" OR "); final StringJoiner whereClause = new StringJoiner(" OR ");
final StringJoiner havingClause = new StringJoiner(" AND "); final StringJoiner havingClause = new StringJoiner(" AND ");
String artifactTypeFilter = null; // Capture all types by default.
ArtifactTypeFilter artifactTypeFilter = new ArtifactTypeFilter(SearchData.Type.DOMAIN.getArtifactTypes());
boolean hasDateTimeFilter = false; boolean hasDateTimeFilter = false;
for (AbstractFilter filter : filters) { for (AbstractFilter filter : filters) {
if (filter instanceof ArtifactTypeFilter) { if (filter instanceof ArtifactTypeFilter) {
artifactTypeFilter = ((ArtifactTypeFilter) filter) // Replace with user defined types.
.getWhereClause(Arrays.asList(TSK_WEB_ACCOUNT_TYPE)); artifactTypeFilter = ((ArtifactTypeFilter) filter);
} else if (!(filter instanceof DataSourceFilter) && !filter.useAlternateFilter()) { } else if (!(filter instanceof DataSourceFilter) && !filter.useAlternateFilter()) {
if (filter instanceof ArtifactDateRangeFilter) { if (filter instanceof ArtifactDateRangeFilter) {
hasDateTimeFilter = true; hasDateTimeFilter = true;
@ -240,7 +241,7 @@ class DomainSearchCacheLoader extends CacheLoader<SearchKey, Map<GroupKey, List<
havingClause.add("SUM(CASE WHEN " + domainAttributeFilter + " THEN 1 ELSE 0 END) > 0"); havingClause.add("SUM(CASE WHEN " + domainAttributeFilter + " THEN 1 ELSE 0 END) > 0");
return Pair.of( return Pair.of(
whereClause.toString() + ((artifactTypeFilter != null) ? " AND (" + artifactTypeFilter + ")" : ""), whereClause.toString() + " AND (" + artifactTypeFilter.getWhereClause(Arrays.asList(TSK_WEB_ACCOUNT_TYPE)) + ")",
havingClause.toString() havingClause.toString()
); );
} }

View File

@ -151,7 +151,7 @@ public class ResultDomain extends Result {
} }
@Override @Override
public Content getDataSource() throws TskCoreException { public Content getDataSource() {
return this.dataSource; return this.dataSource;
} }

View File

@ -36,7 +36,13 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
public final class SearchData { public final class SearchData {
private final static long BYTES_PER_MB = 1000000; private final static long BYTES_PER_MB = 1000000;
private static final Set<BlackboardArtifact.ARTIFACT_TYPE> DOMAIN_ARTIFACT_TYPES = EnumSet.of(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CACHE, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY); private static final Set<BlackboardArtifact.ARTIFACT_TYPE> DOMAIN_ARTIFACT_TYPES =
EnumSet.of(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK,
BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CACHE,
BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE,
BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD,
BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY,
BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY);
/** /**

View File

@ -33,6 +33,7 @@ import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -206,7 +207,7 @@ public class SearchFiltering {
*/ */
public static class ArtifactTypeFilter extends AbstractFilter { public static class ArtifactTypeFilter extends AbstractFilter {
private final List<ARTIFACT_TYPE> types; private final Collection<ARTIFACT_TYPE> types;
/** /**
* Construct a new ArtifactTypeFilter. * Construct a new ArtifactTypeFilter.
@ -214,7 +215,7 @@ public class SearchFiltering {
* @param types The list of BlackboardArtifact types to include in * @param types The list of BlackboardArtifact types to include in
* results from. * results from.
*/ */
public ArtifactTypeFilter(List<ARTIFACT_TYPE> types) { public ArtifactTypeFilter(Collection<ARTIFACT_TYPE> types) {
this.types = types; this.types = types;
} }
@ -223,8 +224,8 @@ public class SearchFiltering {
* *
* @return The list of artifact types specified by the filter. * @return The list of artifact types specified by the filter.
*/ */
public List<ARTIFACT_TYPE> getTypes() { public Collection<ARTIFACT_TYPE> getTypes() {
return Collections.unmodifiableList(types); return Collections.unmodifiableCollection(types);
} }
private StringJoiner joinStandardArtifactTypes() { private StringJoiner joinStandardArtifactTypes() {

View File

@ -72,6 +72,18 @@ MiniTimelineArtifactListPanel.value.noValue=No value available.
MiniTimelineDateListPanel.countColumn.name=Count MiniTimelineDateListPanel.countColumn.name=Count
MiniTimelineDateListPanel.dateColumn.name=Date MiniTimelineDateListPanel.dateColumn.name=Date
MiniTimelineDateListPanel.value.noValue=No value available. MiniTimelineDateListPanel.value.noValue=No value available.
MonthAbbreviation.aprilAbbrev=Apr
MonthAbbreviation.augustAbbrev=Aug
MonthAbbreviation.decemberAbbrev=Dec
MonthAbbreviation.feburaryAbbrev=Feb
MonthAbbreviation.januraryAbbrev=Jan
MonthAbbreviation.julyAbbrev=Jul
MonthAbbreviation.juneAbbrev=Jun
MonthAbbreviation.marchAbbrev=Mar
MonthAbbreviation.mayAbbrev=May
MonthAbbreviation.novemberAbbrev=Nov
MonthAbbreviation.octoberAbbrev=Oct
MonthAbbreviation.septemberAbbrev=Sep
ObjectDetectedFilterPanel.error.text=At least one object type name must be selected. ObjectDetectedFilterPanel.error.text=At least one object type name must be selected.
ParentFolderFilterPanel.error.text=At least one parent path must be entered. ParentFolderFilterPanel.error.text=At least one parent path must be entered.
PastOccurrencesFilterPanel.error.text=At least one value in the past occurrence filter must be selected. PastOccurrencesFilterPanel.error.text=At least one value in the past occurrence filter must be selected.

View File

@ -22,15 +22,16 @@ import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Point; import java.awt.Point;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.text.SimpleDateFormat; import java.time.Instant;
import java.util.Date; import java.time.ZonedDateTime;
import java.util.Locale; import java.util.TimeZone;
import javax.swing.ImageIcon; import javax.swing.ImageIcon;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JList; import javax.swing.JList;
import javax.swing.ListCellRenderer; import javax.swing.ListCellRenderer;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
/** /**
* Class which displays a preview and details about a domain. * Class which displays a preview and details about a domain.
@ -39,7 +40,6 @@ class DomainSummaryPanel extends javax.swing.JPanel implements ListCellRenderer<
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Color SELECTION_COLOR = new Color(0, 120, 215); private static final Color SELECTION_COLOR = new Color(0, 120, 215);
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("MMM dd yyyy", Locale.getDefault());
/** /**
* Creates new form DomainPanel. * Creates new form DomainPanel.
@ -149,8 +149,9 @@ class DomainSummaryPanel extends javax.swing.JPanel implements ListCellRenderer<
@Override @Override
public Component getListCellRendererComponent(JList<? extends DomainWrapper> list, DomainWrapper value, int index, boolean isSelected, boolean cellHasFocus) { public Component getListCellRendererComponent(JList<? extends DomainWrapper> list, DomainWrapper value, int index, boolean isSelected, boolean cellHasFocus) {
domainNameLabel.setText(value.getResultDomain().getDomain()); domainNameLabel.setText(value.getResultDomain().getDomain());
String startDate = dateFormat.format(new Date(value.getResultDomain().getActivityStart() * 1000)); TimeZone timeZone = ContentUtils.getTimeZone(value.getResultDomain().getDataSource());
String endDate = dateFormat.format(new Date(value.getResultDomain().getActivityEnd() * 1000)); String startDate = formatDate(value.getResultDomain().getActivityStart(), timeZone);
String endDate = formatDate(value.getResultDomain().getActivityEnd(), timeZone);
activityLabel.setText(Bundle.DomainSummaryPanel_activity_text(startDate, endDate)); activityLabel.setText(Bundle.DomainSummaryPanel_activity_text(startDate, endDate));
totalVisitsLabel.setText(Bundle.DomainSummaryPanel_totalPages_text() + value.getResultDomain().getTotalPageViews()); totalVisitsLabel.setText(Bundle.DomainSummaryPanel_totalPages_text() + value.getResultDomain().getTotalPageViews());
pagesLabel.setText(Bundle.DomainSummaryPanel_pages_text() + value.getResultDomain().getPageViewsInLast60Days()); pagesLabel.setText(Bundle.DomainSummaryPanel_pages_text() + value.getResultDomain().getPageViewsInLast60Days());
@ -166,6 +167,22 @@ class DomainSummaryPanel extends javax.swing.JPanel implements ListCellRenderer<
return this; return this;
} }
/**
* Formats an epoch time in a given time zone using the following pattern
*
* MMM dd YYYY
*
* The pattern below is formatted manually to reuse the MonthAbbreviation utility.
*/
private String formatDate(long epochSeconds, TimeZone timeZone) {
Instant epochSecondsAsInstant = Instant.ofEpochSecond(epochSeconds);
ZonedDateTime dateTime = ZonedDateTime.ofInstant(epochSecondsAsInstant, timeZone.toZoneId());
MonthAbbreviation currentCutOffMonth = MonthAbbreviation.fromMonthValue(dateTime.getMonthValue());
return String.format("%s %02d %04d",
currentCutOffMonth.toString(),
dateTime.getDayOfMonth(), dateTime.getYear());
}
@ThreadConfined(type = ThreadConfined.ThreadType.AWT) @ThreadConfined(type = ThreadConfined.ThreadType.AWT)
@Override @Override
public String getToolTipText(MouseEvent event) { public String getToolTipText(MouseEvent event) {

View File

@ -0,0 +1,80 @@
/*
* Autopsy
*
* Copyright 2020 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.discovery.ui;
import org.openide.util.NbBundle;
/**
* Utility for representing month abbreviations
*/
@NbBundle.Messages({
"MonthAbbreviation.januraryAbbrev=Jan",
"MonthAbbreviation.feburaryAbbrev=Feb",
"MonthAbbreviation.marchAbbrev=Mar",
"MonthAbbreviation.aprilAbbrev=Apr",
"MonthAbbreviation.mayAbbrev=May",
"MonthAbbreviation.juneAbbrev=Jun",
"MonthAbbreviation.julyAbbrev=Jul",
"MonthAbbreviation.augustAbbrev=Aug",
"MonthAbbreviation.septemberAbbrev=Sep",
"MonthAbbreviation.octoberAbbrev=Oct",
"MonthAbbreviation.novemberAbbrev=Nov",
"MonthAbbreviation.decemberAbbrev=Dec"
})
public enum MonthAbbreviation {
JANURARY(Bundle.MonthAbbreviation_januraryAbbrev()),
FEBURARY(Bundle.MonthAbbreviation_feburaryAbbrev()),
MARCH(Bundle.MonthAbbreviation_marchAbbrev()),
APRIL(Bundle.MonthAbbreviation_aprilAbbrev()),
MAY(Bundle.MonthAbbreviation_mayAbbrev()),
JUNE(Bundle.MonthAbbreviation_juneAbbrev()),
JULY(Bundle.MonthAbbreviation_julyAbbrev()),
AUGUST(Bundle.MonthAbbreviation_augustAbbrev()),
SEPTEMBER(Bundle.MonthAbbreviation_septemberAbbrev()),
OCTOBER(Bundle.MonthAbbreviation_octoberAbbrev()),
NOVEMBER(Bundle.MonthAbbreviation_novemberAbbrev()),
DECEMBER(Bundle.MonthAbbreviation_decemberAbbrev());
private final String abbreviation;
MonthAbbreviation(String abbreviation) {
this.abbreviation = abbreviation;
}
@Override
public String toString() {
return this.abbreviation;
}
/**
* Converts a month value (1-12) to the appropriate abbreviation.
*
* @param value Month value (1-12).
* @return Abbreviation matching the month value, null if not found.
*/
public static MonthAbbreviation fromMonthValue(int value) {
MonthAbbreviation[] months = MonthAbbreviation.values();
for(int i = 0; i < months.length; i++) {
if (i + 1 == value) {
return months[i];
}
}
return null;
}
}