From 1f20b4e2cb37956a7bdada872eefd77ec9f9c384 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 16 Nov 2020 09:20:52 -0500 Subject: [PATCH 01/42] adding popup menu for items --- .../datamodel/UserActivitySummary.java | 155 ++++++++++-------- .../ui/UserActivityPanel.java | 76 +++++++-- .../uiutils/CellModelTableCellRenderer.java | 79 ++++++++- .../uiutils/JTablePanel.java | 83 ++++++++-- .../uiutils/ViewArtifactAction.java | 51 ++++++ .../datamodel/UserActivitySummaryTest.java | 24 +-- 6 files changed, 356 insertions(+), 112 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/ViewArtifactAction.java diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java index 16da6f5c4b..7391b0ef8c 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java @@ -108,8 +108,8 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { private static final String NTOS_BOOT_IDENTIFIER = "NTOSBOOT"; private static final String WINDOWS_PREFIX = "/WINDOWS"; - private static final Comparator TOP_ACCOUNT_RESULT_DATE_COMPARE = (a, b) -> a.getLastAccess().compareTo(b.getLastAccess()); - private static final Comparator TOP_WEBSEARCH_RESULT_DATE_COMPARE = (a, b) -> a.getDateAccessed().compareTo(b.getDateAccessed()); + private static final Comparator TOP_ACCOUNT_RESULT_DATE_COMPARE = (a, b) -> a.getLastAccessed().compareTo(b.getLastAccessed()); + private static final Comparator TOP_WEBSEARCH_RESULT_DATE_COMPARE = (a, b) -> a.getLastAccessed().compareTo(b.getLastAccessed()); /** * Sorts TopProgramsResults pushing highest run time count then most recent @@ -126,8 +126,8 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { // second priority for sorting is the last run date // if non-0, this is the return value for the comparator int lastRunCompare = nullableCompare( - a.getLastRun() == null ? null : a.getLastRun().getTime(), - b.getLastRun() == null ? null : b.getLastRun().getTime()); + a.getLastAccessed() == null ? null : a.getLastAccessed().getTime(), + b.getLastAccessed() == null ? null : b.getLastAccessed().getTime()); if (lastRunCompare != 0) { return -lastRunCompare; @@ -219,14 +219,14 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { return Collections.emptyList(); } - Pair>> mostRecentAndGroups = getDomainGroupsAndMostRecent(dataSource); + Pair>>> mostRecentAndGroups = getDomainGroupsAndMostRecent(dataSource); // if no recent domains, return accordingly if (mostRecentAndGroups.getKey() == null || mostRecentAndGroups.getValue().size() == 0) { return Collections.emptyList(); } final long mostRecentMs = mostRecentAndGroups.getLeft(); - Map> groups = mostRecentAndGroups.getRight(); + Map>> groups = mostRecentAndGroups.getRight(); return groups.entrySet().stream() .map(entry -> getDomainsResult(entry.getKey(), entry.getValue(), mostRecentMs)) @@ -243,17 +243,20 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * within DOMAIN_WINDOW_MS of mostRecentMs. * * @param domain The domain. - * @param visits The number of visits. + * @param visits The list of the artifact and its associated time in milliseconds. * @param mostRecentMs The most recent visit of any domain. * * @return The TopDomainsResult or null if no visits to this domain within * 30 days of mostRecentMs. */ - private TopDomainsResult getDomainsResult(String domain, List visits, long mostRecentMs) { + private TopDomainsResult getDomainsResult(String domain, List> visits, long mostRecentMs) { long visitCount = 0; Long thisMostRecentMs = null; + BlackboardArtifact thisMostRecentArtifact = null; - for (Long visitMs : visits) { + for (Pair visitInstance : visits) { + BlackboardArtifact artifact = visitInstance.getLeft(); + long visitMs = visitInstance.getRight(); // make sure that visit is within window of mostRecentMS; otherwise skip it. if (visitMs + DOMAIN_WINDOW_MS < mostRecentMs) { continue; @@ -261,6 +264,10 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { // if visit is within window, increment the count and get most recent visitCount++; + if (visitMs > thisMostRecentMs) { + thisMostRecentMs = visitMs; + thisMostRecentArtifact = artifact; + } thisMostRecentMs = getMax(thisMostRecentMs, visitMs); } @@ -269,7 +276,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { return null; } else { // create a top domain result with the domain, count, and most recent visit date - return new TopDomainsResult(domain, visitCount, new Date(thisMostRecentMs)); + return new TopDomainsResult(domain, visitCount, new Date(thisMostRecentMs), thisMostRecentArtifact); } } @@ -282,17 +289,17 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * @return A tuple where the first value is the latest web history accessed * date in milliseconds and the second value maps normalized * (lowercase; trimmed) domain names to when those domains were - * visited. + * visited and the relevant artifact. * * @throws TskCoreException * @throws SleuthkitCaseProviderException */ - private Pair>> getDomainGroupsAndMostRecent(DataSource dataSource) throws TskCoreException, SleuthkitCaseProviderException { + private Pair>>> getDomainGroupsAndMostRecent(DataSource dataSource) throws TskCoreException, SleuthkitCaseProviderException { List artifacts = DataSourceInfoUtilities.getArtifacts(caseProvider.get(), TYPE_WEB_HISTORY, dataSource, TYPE_DATETIME_ACCESSED, DataSourceInfoUtilities.SortOrder.DESCENDING, 0); Long mostRecentMs = null; - Map> domainVisits = new HashMap<>(); + Map>> domainVisits = new HashMap<>(); for (BlackboardArtifact art : artifacts) { Long artifactDateSecs = DataSourceInfoUtilities.getLongOrNull(art, TYPE_DATETIME_ACCESSED); @@ -313,13 +320,13 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { domain = domain.toLowerCase().trim(); // add this visit date to the list of dates for the domain - List domainVisitList = domainVisits.get(domain); + List> domainVisitList = domainVisits.get(domain); if (domainVisitList == null) { domainVisitList = new ArrayList<>(); domainVisits.put(domain, domainVisitList); } - domainVisitList.add(artifactDateMs); + domainVisitList.add(Pair.of(art, artifactDateMs)); } return Pair.of(mostRecentMs, domainVisits); @@ -355,7 +362,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { String searchString = DataSourceInfoUtilities.getStringOrNull(artifact, TYPE_TEXT); Date dateAccessed = DataSourceInfoUtilities.getDateOrNull(artifact, TYPE_DATETIME_ACCESSED); return (StringUtils.isNotBlank(searchString) && dateAccessed != null) - ? new TopWebSearchResult(searchString, dateAccessed) + ? new TopWebSearchResult(searchString, dateAccessed, artifact) : null; } @@ -477,7 +484,8 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { DataSourceInfoUtilities.getStringOrNull(artifact, TYPE_DEVICE_ID), DataSourceInfoUtilities.getDateOrNull(artifact, TYPE_DATETIME), DataSourceInfoUtilities.getStringOrNull(artifact, TYPE_DEVICE_MAKE), - DataSourceInfoUtilities.getStringOrNull(artifact, TYPE_DEVICE_MODEL) + DataSourceInfoUtilities.getStringOrNull(artifact, TYPE_DEVICE_MODEL), + artifact ); }) // remove Root Hub identifier @@ -667,7 +675,8 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { programName, path, longCount, - DataSourceInfoUtilities.getDateOrNull(artifact, TYPE_DATETIME) + DataSourceInfoUtilities.getDateOrNull(artifact, TYPE_DATETIME), + artifact ); } @@ -762,11 +771,15 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { res -> Pair.of(res.getProgramName(), res.getProgramPath()), res -> res, (res1, res2) -> { + Long maxRunTimes = getMax(res1.getRunTimes(), res2.getRunTimes()); + Date maxDate = getMax(res1.getLastAccessed(), res2.getLastAccessed()); + TopProgramsResult maxResult = TOP_PROGRAMS_RESULT_COMPARE.compare(res1, res2) >= 0 ? res1 : res2; return new TopProgramsResult( - res1.getProgramName(), - res1.getProgramPath(), - getMax(res1.getRunTimes(), res2.getRunTimes()), - getMax(res1.getLastRun(), res2.getLastRun())); + maxResult.getProgramName(), + maxResult.getProgramPath(), + maxRunTimes, + maxDate, + maxResult.getArtifact()); })).values(); List orderedResults = results.stream() @@ -779,7 +792,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { // if run times / last run information is available, the first item should have some value, // and then the items should be limited accordingly. if (isPositiveNum(topResult.getRunTimes()) - || (topResult.getLastRun() != null && isPositiveNum(topResult.getLastRun().getTime()))) { + || (topResult.getLastAccessed() != null && isPositiveNum(topResult.getLastAccessed().getTime()))) { return orderedResults.stream().limit(count).collect(Collectors.toList()); } } @@ -787,25 +800,59 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { // otherwise return the alphabetized list with no limit applied. return orderedResults; } + + /** + * Base class including date of last access and the relevant blackboard artifact. + */ + public static class LastAccessedArtifact { + private final Date lastAccessed; + private final BlackboardArtifact artifact; + + /** + * Main constructor. + * @param lastAccessed The date of last access. + * @param artifact The relevant blackboard artifact. + */ + public LastAccessedArtifact(Date lastAccessed, BlackboardArtifact artifact) { + this.lastAccessed = lastAccessed; + this.artifact = artifact; + } + + /** + * @return The date of last access. + */ + public Date getLastAccessed() { + return lastAccessed; + } + + /** + * @return The associated artifact. + */ + public BlackboardArtifact getArtifact() { + return artifact; + } + } + /** * Object containing information about a web search artifact. */ - public static class TopWebSearchResult { + public static class TopWebSearchResult extends LastAccessedArtifact { private final String searchString; - private final Date dateAccessed; private String translatedResult; + /** * Main constructor. * * @param searchString The search string. * @param dateAccessed The latest date searched. + * @param artifact The relevant blackboard artifact. */ - public TopWebSearchResult(String searchString, Date dateAccessed) { + public TopWebSearchResult(String searchString, Date dateAccessed, BlackboardArtifact artifact) { + super(dateAccessed, artifact); this.searchString = searchString; - this.dateAccessed = dateAccessed; } /** @@ -830,22 +877,14 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { public String getSearchString() { return searchString; } - - /** - * @return The date for the search. - */ - public Date getDateAccessed() { - return dateAccessed; - } } /** * A record of a device attached. */ - public static class TopDeviceAttachedResult { + public static class TopDeviceAttachedResult extends LastAccessedArtifact { private final String deviceId; - private final Date dateAccessed; private final String deviceMake; private final String deviceModel; @@ -856,10 +895,11 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * @param dateAccessed The date last attached. * @param deviceMake The device make. * @param deviceModel The device model. + * @param artifact The relevant blackboard artifact. */ - public TopDeviceAttachedResult(String deviceId, Date dateAccessed, String deviceMake, String deviceModel) { + public TopDeviceAttachedResult(String deviceId, Date dateAccessed, String deviceMake, String deviceModel, BlackboardArtifact artifact) { + super(dateAccessed, artifact); this.deviceId = deviceId; - this.dateAccessed = dateAccessed; this.deviceMake = deviceMake; this.deviceModel = deviceModel; } @@ -871,13 +911,6 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { return deviceId; } - /** - * @return The date last attached. - */ - public Date getDateAccessed() { - return dateAccessed; - } - /** * @return The device make. */ @@ -923,7 +956,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { /** * @return The date the account was last accessed. */ - public Date getLastAccess() { + public Date getLastAccessed() { return lastAccess; } } @@ -931,11 +964,10 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { /** * Describes a result of a program run on a datasource. */ - public static class TopDomainsResult { + public static class TopDomainsResult extends LastAccessedArtifact { private final String domain; private final Long visitTimes; - private final Date lastVisit; /** * Describes a top domain result. @@ -943,11 +975,12 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * @param domain The domain. * @param visitTimes The number of times it was visited. * @param lastVisit The date of the last visit. + * @param artifact The relevant blackboard artifact. */ - public TopDomainsResult(String domain, Long visitTimes, Date lastVisit) { + public TopDomainsResult(String domain, Long visitTimes, Date lastVisit, BlackboardArtifact artifact) { + super(lastVisit, artifact); this.domain = domain; this.visitTimes = visitTimes; - this.lastVisit = lastVisit; } /** @@ -963,24 +996,16 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { public Long getVisitTimes() { return visitTimes; } - - /** - * @return The date of the last visit. - */ - public Date getLastVisit() { - return lastVisit; - } } /** * Describes a result of a program run on a datasource. */ - public static class TopProgramsResult { + public static class TopProgramsResult extends LastAccessedArtifact { private final String programName; private final String programPath; private final Long runTimes; - private final Date lastRun; /** * Main constructor. @@ -988,12 +1013,13 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * @param programName The name of the program. * @param programPath The path of the program. * @param runTimes The number of runs. + * @param artifact The relevant blackboard artifact. */ - TopProgramsResult(String programName, String programPath, Long runTimes, Date lastRun) { + TopProgramsResult(String programName, String programPath, Long runTimes, Date lastRun, BlackboardArtifact artifact) { + super(lastRun, artifact); this.programName = programName; this.programPath = programPath; this.runTimes = runTimes; - this.lastRun = lastRun; } /** @@ -1016,12 +1042,5 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { public Long getRunTimes() { return runTimes; } - - /** - * @return The last time the program was run or null if not present. - */ - public Date getLastRun() { - return lastRun; - } } } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java index baab54217c..9ed422845a 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java @@ -29,16 +29,21 @@ import org.apache.commons.lang.StringUtils; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.datasourcesummary.datamodel.IngestModuleCheckUtil; import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.LastAccessedArtifact; import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopAccountResult; import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopDeviceAttachedResult; import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopWebSearchResult; import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopDomainsResult; import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopProgramsResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.DefaultCellModel; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.DefaultMenuItem; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.MenuItem; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel.ColumnModel; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.ViewArtifactAction; +import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.DataSource; /** @@ -61,7 +66,8 @@ import org.sleuthkit.datamodel.DataSource; "UserActivityPanel_TopDeviceAttachedTableModel_dateAccessed_header=Last Accessed", "UserActivityPanel_TopAccountTableModel_accountType_header=Account Type", "UserActivityPanel_TopAccountTableModel_lastAccess_header=Last Accessed", - "UserActivityPanel_noDataExists=No communication data exists"}) + "UserActivityPanel_noDataExists=No communication data exists", + "UserActivityPanel_goToArtifact=Go to Artifact"}) public class UserActivityPanel extends BaseDataSourceSummaryPanel { private static final long serialVersionUID = 1L; @@ -74,6 +80,14 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { private static final String ANDROID_FACTORY = "org.python.proxies.module$AndroidModuleFactory"; private static final String ANDROID_MODULE_NAME = "Android Analyzer"; + private static List getArtifactPopup(BlackboardArtifact artifact) { + return artifact == null ? null : Arrays.asList(new DefaultMenuItem(Bundle.UserActivityPanel_goToArtifact(), new ViewArtifactAction(artifact))); + } + + private static List getPopup(LastAccessedArtifact record) { + return record == null ? null : getArtifactPopup(record.getArtifact()); + } + /** * Gets a string formatted date or returns empty string if the date is null. * @@ -92,7 +106,8 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { Bundle.UserActivityPanel_TopProgramsTableModel_name_header(), (prog) -> { return new DefaultCellModel(prog.getProgramName()) - .setTooltip(prog.getProgramPath()); + .setTooltip(prog.getProgramPath()) + .setPopupMenu(getPopup(prog)); }, 250), // program folder column @@ -103,7 +118,8 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { getShortFolderName( prog.getProgramPath(), prog.getProgramName())) - .setTooltip(prog.getProgramPath()); + .setTooltip(prog.getProgramPath()) + .setPopupMenu(getPopup(prog)); }, 150), // run count column @@ -111,13 +127,17 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { Bundle.UserActivityPanel_TopProgramsTableModel_count_header(), (prog) -> { String runTimes = prog.getRunTimes() == null ? "" : Long.toString(prog.getRunTimes()); - return new DefaultCellModel(runTimes); + return new DefaultCellModel(runTimes) + .setPopupMenu(getPopup(prog)); }, 80), // last run date column new ColumnModel<>( Bundle.UserActivityPanel_TopProgramsTableModel_lastrun_header(), - (prog) -> new DefaultCellModel(getFormatted(prog.getLastRun())), + (prog) -> { + return new DefaultCellModel(getFormatted(prog.getLastAccessed())) + .setPopupMenu(getPopup(prog)); + }, 150) )) .setKeyFunction((prog) -> prog.getProgramPath() + ":" + prog.getProgramName()); @@ -127,20 +147,24 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { // domain column new ColumnModel( Bundle.UserActivityPanel_TopDomainsTableModel_domain_header(), - (recentDomain) -> new DefaultCellModel(recentDomain.getDomain()), + (recentDomain) -> { + return new DefaultCellModel(recentDomain.getDomain()) + .setPopupMenu(getPopup(recentDomain)); + }, 250), // count column new ColumnModel<>( Bundle.UserActivityPanel_TopDomainsTableModel_count_header(), (recentDomain) -> { String visitTimes = recentDomain.getVisitTimes() == null ? "" : Long.toString(recentDomain.getVisitTimes()); - return new DefaultCellModel(visitTimes); + return new DefaultCellModel(visitTimes) + .setPopupMenu(getPopup(recentDomain)); }, 100), // last accessed column new ColumnModel<>( Bundle.UserActivityPanel_TopDomainsTableModel_lastAccess_header(), - (recentDomain) -> new DefaultCellModel(getFormatted(recentDomain.getLastVisit())), + (recentDomain) -> new DefaultCellModel(getFormatted(recentDomain.getLastAccessed())), 150) )) .setKeyFunction((domain) -> domain.getDomain()); @@ -150,19 +174,28 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { // search string column new ColumnModel( Bundle.UserActivityPanel_TopWebSearchTableModel_searchString_header(), - (webSearch) -> new DefaultCellModel(webSearch.getSearchString()), + (webSearch) -> { + return new DefaultCellModel(webSearch.getSearchString()) + .setPopupMenu(getPopup(webSearch)); + }, 250 ), // last accessed new ColumnModel<>( Bundle.UserActivityPanel_TopWebSearchTableModel_dateAccessed_header(), - (webSearch) -> new DefaultCellModel(getFormatted(webSearch.getDateAccessed())), + (webSearch) -> { + return new DefaultCellModel(getFormatted(webSearch.getLastAccessed())) + .setPopupMenu(getPopup(webSearch)); + }, 150 ), // translated value new ColumnModel<>( Bundle.UserActivityPanel_TopWebSearchTableModel_translatedResult_header(), - (webSearch) -> new DefaultCellModel(webSearch.getTranslatedResult()), + (webSearch) -> { + return new DefaultCellModel(webSearch.getTranslatedResult()) + .setPopupMenu(getPopup(webSearch)); + }, 250 ) )) @@ -173,13 +206,19 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { // device id column new ColumnModel( Bundle.UserActivityPanel_TopDeviceAttachedTableModel_deviceId_header(), - (device) -> new DefaultCellModel(device.getDeviceId()), + (device) -> { + return new DefaultCellModel(device.getDeviceId()) + .setPopupMenu(getPopup(device)); + }, 250 ), // last accessed new ColumnModel<>( Bundle.UserActivityPanel_TopDeviceAttachedTableModel_dateAccessed_header(), - (device) -> new DefaultCellModel(getFormatted(device.getDateAccessed())), + (device) -> { + return new DefaultCellModel(getFormatted(device.getLastAccessed())) + .setPopupMenu(getPopup(device)); + }, 150 ), // make and model @@ -191,7 +230,8 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { String makeModelString = (make.isEmpty() || model.isEmpty()) ? make + model : String.format("%s - %s", make, model); - return new DefaultCellModel(makeModelString); + return new DefaultCellModel(makeModelString) + .setPopupMenu(getPopup(device)); }, 250 ) @@ -209,7 +249,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { // last accessed new ColumnModel<>( Bundle.UserActivityPanel_TopAccountTableModel_lastAccess_header(), - (account) -> new DefaultCellModel(getFormatted(account.getLastAccess())), + (account) -> new DefaultCellModel(getFormatted(account.getLastAccessed())), 150 ) )) @@ -227,7 +267,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { private final List> dataFetchComponents; private final UserActivitySummary userActivityData; - + /** * Creates a new UserActivityPanel. */ @@ -239,7 +279,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { * Creates a new UserActivityPanel. * * @param userActivityData Class from which to obtain remaining user - * activity data. + * activity data. */ public UserActivityPanel(UserActivitySummary userActivityData) { super(userActivityData); @@ -295,7 +335,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { /** * Queries DataSourceTopProgramsSummary instance for short folder name. * - * @param path The path for the application. + * @param path The path for the application. * @param appName The application name. * * @return The underlying short folder name if one exists. diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/CellModelTableCellRenderer.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/CellModelTableCellRenderer.java index 7131dff6c2..02d6d6b34b 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/CellModelTableCellRenderer.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/CellModelTableCellRenderer.java @@ -20,6 +20,9 @@ package org.sleuthkit.autopsy.datasourcesummary.uiutils; import java.awt.Component; import java.awt.Insets; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import javax.swing.BorderFactory; import javax.swing.JLabel; import javax.swing.JTable; @@ -49,7 +52,7 @@ public class CellModelTableCellRenderer extends DefaultTableCellRenderer { * Constructor for a HorizontalAlign enum. * * @param jlabelAlignment The corresponding JLabel horizontal alignment - * number. + * number. */ HorizontalAlign(int jlabelAlignment) { this.jlabelAlignment = jlabelAlignment; @@ -57,13 +60,57 @@ public class CellModelTableCellRenderer extends DefaultTableCellRenderer { /** * @return The corresponding JLabel horizontal alignment (i.e. - * JLabel.LEFT). + * JLabel.LEFT). */ int getJLabelAlignment() { return this.jlabelAlignment; } } + /** + * A menu item to be used within a popup menu. + */ + public interface MenuItem { + + /** + * @return The title for that popup menu item. + */ + String getTitle(); + + /** + * @return The action if that popup menu item is clicked. + */ + Runnable getAction(); + } + + /** + * Default implementation of a menu item. + */ + public static class DefaultMenuItem implements MenuItem { + + private final String title; + private final Runnable action; + + /** + * Main constructor. + * @param title The title for the menu item. + * @param action The action should the menu item be clicked. + */ + public DefaultMenuItem(String title, Runnable action) { + this.title = title; + this.action = action; + } + + public String getTitle() { + return title; + } + + public Runnable getAction() { + return action; + } + + } + /** * Basic interface for a cell model. */ @@ -88,6 +135,12 @@ public class CellModelTableCellRenderer extends DefaultTableCellRenderer { * @return The insets for the cell text. */ Insets getInsets(); + + /** + * @return The popup menu associated with this cell or null if no popup + * menu should be shown for this cell. + */ + List getPopupMenu(); } /** @@ -99,6 +152,7 @@ public class CellModelTableCellRenderer extends DefaultTableCellRenderer { private String tooltip; private HorizontalAlign horizontalAlignment; private Insets insets; + private List popupMenu; /** * Main constructor. @@ -166,6 +220,23 @@ public class CellModelTableCellRenderer extends DefaultTableCellRenderer { return this; } + @Override + public List getPopupMenu() { + return popupMenu == null ? null : Collections.unmodifiableList(popupMenu); + } + + /** + * Sets the list of items for a popup menu + * @param popupMenu + * @return As a utility, returns this. + */ + public DefaultCellModel setPopupMenu(List popupMenu) { + this.popupMenu = popupMenu == null ? null : new ArrayList<>(popupMenu); + return this; + } + + + @Override public String toString() { return getText(); @@ -192,8 +263,8 @@ public class CellModelTableCellRenderer extends DefaultTableCellRenderer { * Customizes the jlabel to match the column model and cell model provided. * * @param defaultCell The cell to customize that will be displayed in the - * jtable. - * @param cellModel The cell model for this cell. + * jtable. + * @param cellModel The cell model for this cell. * * @return The provided defaultCell. */ diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/JTablePanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/JTablePanel.java index 550f334d7a..ed6e5f14ad 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/JTablePanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/JTablePanel.java @@ -20,19 +20,26 @@ package org.sleuthkit.autopsy.datasourcesummary.uiutils; import java.awt.BorderLayout; import java.awt.Graphics; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; import java.util.Collections; import java.util.List; import java.util.function.Function; import java.util.stream.Collectors; import javax.swing.JComponent; import javax.swing.JLayer; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.plaf.LayerUI; import javax.swing.table.DefaultTableColumnModel; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; +import org.apache.commons.collections.CollectionUtils; import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.CellModel; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.MenuItem; /** * A table that displays a list of items and also can display messages for @@ -91,9 +98,9 @@ public class JTablePanel extends AbstractLoadableComponent> { /** * Constructor for a DataResultColumnModel. * - * @param headerTitle The title for the column. + * @param headerTitle The title for the column. * @param cellRenderer The method that generates a CellModel for the - * column based on the data. + * column based on the data. */ public ColumnModel(String headerTitle, Function cellRenderer) { this(headerTitle, cellRenderer, null); @@ -102,10 +109,10 @@ public class JTablePanel extends AbstractLoadableComponent> { /** * Constructor for a DataResultColumnModel. * - * @param headerTitle The title for the column. + * @param headerTitle The title for the column. * @param cellRenderer The method that generates a CellModel for the - * column based on the data. - * @param width The preferred width of the column. + * column based on the data. + * @param width The preferred width of the column. */ public ColumnModel(String headerTitle, Function cellRenderer, Integer width) { this.headerTitle = headerTitle; @@ -122,7 +129,7 @@ public class JTablePanel extends AbstractLoadableComponent> { /** * @return The method that generates a CellModel for the column based on - * the data. + * the data. */ public Function getCellRenderer() { return cellRenderer; @@ -187,6 +194,62 @@ public class JTablePanel extends AbstractLoadableComponent> { return new DefaultListTableModel(columnRenderers); } + /** + * Sets up a table mouse listener to trigger a popup menu if the cell + * clicked has a popup menu. + * + * @param tablePanel Th JTablePanel instance. + */ + private static void setPopupListener(final JTablePanel tablePanel) { + final JTable table = tablePanel.table; + final ListTableModel tableModel = tablePanel.tableModel; + + // add mouse listener to table for popup menu item click + tablePanel.table.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + // make sure click event isn't primary button and table is present + if (e.getButton() != MouseEvent.BUTTON1 && tablePanel.table != null) { + int row = table.rowAtPoint(e.getPoint()); + int col = table.columnAtPoint(e.getPoint()); + + // make sure there is a value at the row,col of click event. + if (tableModel != null + && row > 0 && row < tableModel.getRowCount() + && col > 0 && col < tableModel.getColumnCount()) { + + // select the row + table.setRowSelectionInterval(row, row); + + Object cellModelObj = tableModel.getValueAt(row, col); + // if the object at that cell is a cell model object. + if (cellModelObj instanceof CellModel) { + CellModel cellModel = (CellModel) cellModelObj; + List menuItems = cellModel.getPopupMenu(); + + // if there are menu items, show a popup menu for + // this item with all the menu items. + if (CollectionUtils.isNotEmpty(menuItems)) { + final JPopupMenu popupMenu = new JPopupMenu(); + for (MenuItem mItem : menuItems) { + JMenuItem jMenuItem = new JMenuItem(mItem.getTitle()); + if (mItem.getAction() != null) { + jMenuItem.addActionListener((evt) -> mItem.getAction().run()); + } + popupMenu.add(jMenuItem); + } + popupMenu.show(table, e.getX(), e.getY()); + } + } + + } + + } + } + + }); + } + /** * Generates a JTablePanel corresponding to the provided column definitions * where 'T' is the object representing each row. @@ -198,6 +261,7 @@ public class JTablePanel extends AbstractLoadableComponent> { public static JTablePanel getJTablePanel(List> columns) { ListTableModel tableModel = getTableModel(columns); JTablePanel resultTable = new JTablePanel<>(tableModel); + setPopupListener(resultTable); return resultTable.setColumnModel(getTableColumnModel(columns)); } @@ -206,6 +270,7 @@ public class JTablePanel extends AbstractLoadableComponent> { private ListTableModel tableModel; private JTable table; private Function keyFunction = (rowItem) -> rowItem; + private MouseListener tableMouseListener = null; /** * Panel constructor. @@ -263,8 +328,7 @@ public class JTablePanel extends AbstractLoadableComponent> { /** * @return The function for determining the key for a data row. This key is - * used to maintain current selection in the table despite changing - * rows. + * used to maintain current selection in the table despite changing rows. */ public Function getKeyFunction() { return keyFunction; @@ -295,7 +359,7 @@ public class JTablePanel extends AbstractLoadableComponent> { T prevValue = (tableRows != null && prevSelectedRow >= 0 && prevSelectedRow < tableRows.size()) ? this.tableModel.getDataRows().get(prevSelectedRow) : null; - + Object prevKeyValue = (prevValue == null) ? null : this.keyFunction.apply(prevValue); // set the list of data to be shown as either the data or an empty list @@ -330,7 +394,6 @@ public class JTablePanel extends AbstractLoadableComponent> { private void initComponents() { table = new JTable(); table.getTableHeader().setReorderingAllowed(false); - overlayLayer = new Overlay(); tableScrollPane = new JScrollPane(table); JLayer dualLayer = new JLayer<>(tableScrollPane, overlayLayer); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/ViewArtifactAction.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/ViewArtifactAction.java new file mode 100644 index 0000000000..4d7f896984 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/ViewArtifactAction.java @@ -0,0 +1,51 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit 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.datasourcesummary.uiutils; + +import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; +import org.sleuthkit.datamodel.BlackboardArtifact; + +/** + * Action that navigates to an artifact in a tree. + */ +public class ViewArtifactAction implements Runnable { + + private final BlackboardArtifact artifact; + + /** + * Main constructor for this action. + * + * @param artifact The artifact that will be displayed in tree + * DirectoryTreeTopComponent. + */ + public ViewArtifactAction(BlackboardArtifact artifact) { + this.artifact = artifact; + } + + @Override + public void run() { + final DirectoryTreeTopComponent dtc = DirectoryTreeTopComponent.findInstance(); + + // Navigate to the source context artifact. + if (dtc != null && artifact != null) { + dtc.viewArtifact(artifact); + } + } + +} diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java index 0aff8a56b5..dbb32b1124 100644 --- a/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java @@ -296,7 +296,7 @@ public class UserActivitySummaryTest { Assert.assertEquals(acceptedDevice, results.get(0).getDeviceModel()); Assert.assertEquals("MAKE " + acceptedDevice, results.get(0).getDeviceMake()); Assert.assertEquals("ID " + acceptedDevice, results.get(0).getDeviceId()); - Assert.assertEquals(time, results.get(0).getDateAccessed().getTime() / 1000); + Assert.assertEquals(time, results.get(0).getLastAccessed().getTime() / 1000); } /** @@ -377,9 +377,9 @@ public class UserActivitySummaryTest { Assert.assertEquals("Expected two different search queries", 2, results.size()); Assert.assertTrue(query1.equalsIgnoreCase(results.get(0).getSearchString())); - Assert.assertEquals(DAY_SECONDS * 5, results.get(0).getDateAccessed().getTime() / 1000); + Assert.assertEquals(DAY_SECONDS * 5, results.get(0).getLastAccessed().getTime() / 1000); Assert.assertTrue(query2.equalsIgnoreCase(results.get(1).getSearchString())); - Assert.assertEquals(DAY_SECONDS * 3, results.get(1).getDateAccessed().getTime() / 1000); + Assert.assertEquals(DAY_SECONDS * 3, results.get(1).getLastAccessed().getTime() / 1000); } private void webSearchTranslationTest(List queries, boolean hasProvider, String translationSuffix) @@ -573,11 +573,11 @@ public class UserActivitySummaryTest { Assert.assertEquals(2, domains.size()); Assert.assertTrue("Expected " + domain1 + " to be first domain", domain1.equalsIgnoreCase(domains.get(0).getDomain())); - Assert.assertEquals(DAY_SECONDS * DOMAIN_WINDOW_DAYS * 2, domains.get(0).getLastVisit().getTime() / 1000); + Assert.assertEquals(DAY_SECONDS * DOMAIN_WINDOW_DAYS * 2, domains.get(0).getLastAccessed().getTime() / 1000); Assert.assertEquals((Long) 2L, domains.get(0).getVisitTimes()); Assert.assertTrue("Expected " + domain3 + " to be second domain", domain3.equalsIgnoreCase(domains.get(1).getDomain())); - Assert.assertEquals(DAY_SECONDS * DOMAIN_WINDOW_DAYS, domains.get(1).getLastVisit().getTime() / 1000); + Assert.assertEquals(DAY_SECONDS * DOMAIN_WINDOW_DAYS, domains.get(1).getLastAccessed().getTime() / 1000); Assert.assertEquals((Long) 1L, domains.get(1).getVisitTimes()); } @@ -617,7 +617,7 @@ public class UserActivitySummaryTest { Assert.assertEquals(1, domains.size()); Assert.assertTrue("Expected " + domain1 + " to be most recent domain", domain1.equalsIgnoreCase(domains.get(0).getDomain())); - Assert.assertEquals(DAY_SECONDS, domains.get(0).getLastVisit().getTime() / 1000); + Assert.assertEquals(DAY_SECONDS, domains.get(0).getLastAccessed().getTime() / 1000); } /** @@ -654,11 +654,11 @@ public class UserActivitySummaryTest { Assert.assertEquals(2, domains.size()); Assert.assertTrue(domain1.equalsIgnoreCase(domains.get(1).getDomain())); - Assert.assertEquals(6L, domains.get(1).getLastVisit().getTime() / 1000); + Assert.assertEquals(6L, domains.get(1).getLastAccessed().getTime() / 1000); Assert.assertEquals((Long) 2L, domains.get(1).getVisitTimes()); Assert.assertTrue(domain2.equalsIgnoreCase(domains.get(0).getDomain())); - Assert.assertEquals(4L, domains.get(0).getLastVisit().getTime() / 1000); + Assert.assertEquals(4L, domains.get(0).getLastAccessed().getTime() / 1000); Assert.assertEquals((Long) 3L, domains.get(0).getVisitTimes()); } @@ -843,7 +843,7 @@ public class UserActivitySummaryTest { // since this may be somewhat variable Assert.assertTrue(expectedItem.getAccountType().equalsIgnoreCase(receivedItem.getAccountType())); - Assert.assertEquals(expectedItem.getLastAccess().getTime(), receivedItem.getLastAccess().getTime()); + Assert.assertEquals(expectedItem.getLastAccessed().getTime(), receivedItem.getLastAccessed().getTime()); } } @@ -1130,17 +1130,17 @@ public class UserActivitySummaryTest { Assert.assertTrue("program1.exe".equalsIgnoreCase(results.get(0).getProgramName())); Assert.assertTrue("/Program Files/another/".equalsIgnoreCase(results.get(0).getProgramPath())); Assert.assertEquals((Long) 31L, results.get(0).getRunTimes()); - Assert.assertEquals((Long) 31L, (Long) (results.get(0).getLastRun().getTime() / 1000)); + Assert.assertEquals((Long) 31L, (Long) (results.get(0).getLastAccessed().getTime() / 1000)); Assert.assertTrue("program1.exe".equalsIgnoreCase(results.get(1).getProgramName())); Assert.assertTrue("/Program Files/etc/".equalsIgnoreCase(results.get(1).getProgramPath())); Assert.assertEquals((Long) 21L, results.get(1).getRunTimes()); - Assert.assertEquals((Long) 31L, (Long) (results.get(1).getLastRun().getTime() / 1000)); + Assert.assertEquals((Long) 31L, (Long) (results.get(1).getLastAccessed().getTime() / 1000)); Assert.assertTrue("program2.exe".equalsIgnoreCase(results.get(2).getProgramName())); Assert.assertTrue("/Program Files/another/".equalsIgnoreCase(results.get(2).getProgramPath())); Assert.assertEquals((Long) 10L, results.get(2).getRunTimes()); - Assert.assertEquals((Long) 22L, (Long) (results.get(2).getLastRun().getTime() / 1000)); + Assert.assertEquals((Long) 22L, (Long) (results.get(2).getLastAccessed().getTime() / 1000)); } private void assertProgramOrder(DataSource ds1, List artifacts, List programNamesReturned) From 3146b97ccbd8e8bee0bacfd1751245ff843889b5 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 16 Nov 2020 13:25:08 -0500 Subject: [PATCH 02/42] closes window if in dialog --- .../datamodel/UserActivitySummary.java | 98 +++++++++---------- .../ui/BaseDataSourceSummaryPanel.java | 52 ++++++---- .../ui/Bundle.properties-MERGED | 1 + .../ui/DataSourceSummaryDialog.java | 11 ++- .../ui/DataSourceSummaryTabbedPane.java | 56 ++++++++--- .../ui/UserActivityPanel.java | 12 ++- .../uiutils/JTablePanel.java | 4 +- .../uiutils/ViewArtifactAction.java | 2 +- 8 files changed, 145 insertions(+), 91 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java index 7391b0ef8c..293dd3c3fc 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java @@ -137,7 +137,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { return (a.getProgramName() == null ? "" : a.getProgramName()) .compareToIgnoreCase((b.getProgramName() == null ? "" : b.getProgramName())); }; - + private static final Set ARTIFACT_UPDATE_TYPE_IDS = new HashSet<>(Arrays.asList( ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID(), ARTIFACT_TYPE.TSK_MESSAGE.getTypeID(), @@ -172,9 +172,9 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * is designed with unit testing in mind since mocked dependencies can be * utilized. * - * @param provider The object providing the current SleuthkitCase. + * @param provider The object providing the current SleuthkitCase. * @param translationService The translation service. - * @param logger The logger to use. + * @param logger The logger to use. */ public UserActivitySummary( SleuthkitCaseProvider provider, @@ -206,7 +206,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * Gets a list of recent domains based on the datasource. * * @param dataSource The datasource to query for recent domains. - * @param count The max count of items to return. + * @param count The max count of items to return. * * @return The list of items retrieved from the database. * @@ -219,14 +219,14 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { return Collections.emptyList(); } - Pair>>> mostRecentAndGroups = getDomainGroupsAndMostRecent(dataSource); + Pair>>> mostRecentAndGroups = getDomainGroupsAndMostRecent(dataSource); // if no recent domains, return accordingly if (mostRecentAndGroups.getKey() == null || mostRecentAndGroups.getValue().size() == 0) { return Collections.emptyList(); } final long mostRecentMs = mostRecentAndGroups.getLeft(); - Map>> groups = mostRecentAndGroups.getRight(); + Map>> groups = mostRecentAndGroups.getRight(); return groups.entrySet().stream() .map(entry -> getDomainsResult(entry.getKey(), entry.getValue(), mostRecentMs)) @@ -242,12 +242,13 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * Creates a TopDomainsResult from data or null if no visit date exists * within DOMAIN_WINDOW_MS of mostRecentMs. * - * @param domain The domain. - * @param visits The list of the artifact and its associated time in milliseconds. + * @param domain The domain. + * @param visits The list of the artifact and its associated time in + * milliseconds. * @param mostRecentMs The most recent visit of any domain. * * @return The TopDomainsResult or null if no visits to this domain within - * 30 days of mostRecentMs. + * 30 days of mostRecentMs. */ private TopDomainsResult getDomainsResult(String domain, List> visits, long mostRecentMs) { long visitCount = 0; @@ -256,15 +257,15 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { for (Pair visitInstance : visits) { BlackboardArtifact artifact = visitInstance.getLeft(); - long visitMs = visitInstance.getRight(); + Long visitMs = visitInstance.getRight(); // make sure that visit is within window of mostRecentMS; otherwise skip it. - if (visitMs + DOMAIN_WINDOW_MS < mostRecentMs) { + if (visitMs == null || visitMs + DOMAIN_WINDOW_MS < mostRecentMs) { continue; } // if visit is within window, increment the count and get most recent visitCount++; - if (visitMs > thisMostRecentMs) { + if (thisMostRecentMs == null || visitMs > thisMostRecentMs) { thisMostRecentMs = visitMs; thisMostRecentArtifact = artifact; } @@ -287,14 +288,14 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * @param dataSource The datasource. * * @return A tuple where the first value is the latest web history accessed - * date in milliseconds and the second value maps normalized - * (lowercase; trimmed) domain names to when those domains were - * visited and the relevant artifact. + * date in milliseconds and the second value maps normalized (lowercase; + * trimmed) domain names to when those domains were visited and the relevant + * artifact. * * @throws TskCoreException * @throws SleuthkitCaseProviderException */ - private Pair>>> getDomainGroupsAndMostRecent(DataSource dataSource) throws TskCoreException, SleuthkitCaseProviderException { + private Pair>>> getDomainGroupsAndMostRecent(DataSource dataSource) throws TskCoreException, SleuthkitCaseProviderException { List artifacts = DataSourceInfoUtilities.getArtifacts(caseProvider.get(), TYPE_WEB_HISTORY, dataSource, TYPE_DATETIME_ACCESSED, DataSourceInfoUtilities.SortOrder.DESCENDING, 0); @@ -356,7 +357,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * @param artifact The artifact. * * @return The TopWebSearchResult or null if the search string or date - * accessed cannot be determined. + * accessed cannot be determined. */ private static TopWebSearchResult getWebSearchResult(BlackboardArtifact artifact) { String searchString = DataSourceInfoUtilities.getStringOrNull(artifact, TYPE_TEXT); @@ -371,11 +372,10 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * term. * * @param dataSource The data source. - * @param count The maximum number of records to be shown (must be > - * 0). + * @param count The maximum number of records to be shown (must be > 0). * * @return The list of most recent web searches where most recent search - * appears first. + * appears first. * * @throws * org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException @@ -431,7 +431,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * @param original The original text. * * @return The translated text or null if no translation can be determined - * or exists. + * or exists. */ private String getTranslationOrNull(String original) { if (!translationService.hasProvider() || StringUtils.isBlank(original)) { @@ -459,11 +459,10 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * Retrieves most recent devices used by most recent date attached. * * @param dataSource The data source. - * @param count The maximum number of records to be shown (must be > - * 0). + * @param count The maximum number of records to be shown (must be > 0). * * @return The list of most recent devices attached where most recent device - * attached appears first. + * attached appears first. * * @throws * org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException @@ -503,7 +502,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * @param artifact The artifact. * * @return The TopAccountResult or null if the account type or message date - * cannot be determined. + * cannot be determined. */ private static TopAccountResult getMessageAccountResult(BlackboardArtifact artifact) { String type = DataSourceInfoUtilities.getStringOrNull(artifact, TYPE_MESSAGE_TYPE); @@ -517,12 +516,12 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * Obtains a TopAccountResult from a blackboard artifact. The date is * maximum of any found dates for attribute types provided. * - * @param artifact The artifact. + * @param artifact The artifact. * @param messageType The type of message this is. - * @param dateAttrs The date attribute types. + * @param dateAttrs The date attribute types. * * @return The TopAccountResult or null if the account type or max date are - * not provided. + * not provided. */ private static TopAccountResult getAccountResult(BlackboardArtifact artifact, String messageType, BlackboardAttribute.Type... dateAttrs) { String type = messageType; @@ -546,11 +545,10 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * sent. * * @param dataSource The data source. - * @param count The maximum number of records to be shown (must be > - * 0). + * @param count The maximum number of records to be shown (must be > 0). * * @return The list of most recent accounts used where the most recent - * account by last message sent occurs first. + * account by last message sent occurs first. * * @throws * org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException @@ -616,7 +614,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { /** * Determines a short folder name if any. Otherwise, returns empty string. * - * @param strPath The string path. + * @param strPath The string path. * @param applicationName The application name. * * @return The short folder name or empty string if not found. @@ -667,7 +665,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { if (StringUtils.startsWithIgnoreCase(path, WINDOWS_PREFIX)) { return null; } - + Integer count = DataSourceInfoUtilities.getIntOrNull(artifact, TYPE_COUNT); Long longCount = (count == null) ? null : (long) count; @@ -705,7 +703,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * @param long2 Second possibly null long. * * @return Returns the compare value: 1,0,-1 favoring the higher non-null - * value. + * value. */ private static int nullableCompare(Long long1, Long long2) { if (long1 == null && long2 == null) { @@ -730,7 +728,6 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { return longNum != null && longNum > 0; } - /** * Retrieves the top programs results for the given data source limited to * the count provided as a parameter. The highest run times are at the top @@ -740,12 +737,12 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * be ignored and all items will be returned. * * @param dataSource The datasource. If the datasource is null, an empty - * list will be returned. - * @param count The number of results to return. This value must be > 0 - * or an IllegalArgumentException will be thrown. + * list will be returned. + * @param count The number of results to return. This value must be > 0 or + * an IllegalArgumentException will be thrown. * * @return The sorted list and limited to the count if last run or run count - * information is available on any item. + * information is available on any item. * * @throws SleuthkitCaseProviderException * @throws TskCoreException @@ -800,16 +797,19 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { // otherwise return the alphabetized list with no limit applied. return orderedResults; } - + /** - * Base class including date of last access and the relevant blackboard artifact. + * Base class including date of last access and the relevant blackboard + * artifact. */ public static class LastAccessedArtifact { + private final Date lastAccessed; private final BlackboardArtifact artifact; /** * Main constructor. + * * @param lastAccessed The date of last access. * @param artifact The relevant blackboard artifact. */ @@ -832,7 +832,6 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { return artifact; } } - /** * Object containing information about a web search artifact. @@ -842,7 +841,6 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { private final String searchString; private String translatedResult; - /** * Main constructor. * @@ -891,10 +889,10 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { /** * Main constructor. * - * @param deviceId The device id. + * @param deviceId The device id. * @param dateAccessed The date last attached. - * @param deviceMake The device make. - * @param deviceModel The device model. + * @param deviceMake The device make. + * @param deviceModel The device model. * @param artifact The relevant blackboard artifact. */ public TopDeviceAttachedResult(String deviceId, Date dateAccessed, String deviceMake, String deviceModel, BlackboardArtifact artifact) { @@ -939,7 +937,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * Main constructor. * * @param accountType The account type. - * @param lastAccess The date the account was last accessed. + * @param lastAccess The date the account was last accessed. */ public TopAccountResult(String accountType, Date lastAccess) { this.accountType = accountType; @@ -972,9 +970,9 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { /** * Describes a top domain result. * - * @param domain The domain. + * @param domain The domain. * @param visitTimes The number of times it was visited. - * @param lastVisit The date of the last visit. + * @param lastVisit The date of the last visit. * @param artifact The relevant blackboard artifact. */ public TopDomainsResult(String domain, Long visitTimes, Date lastVisit, BlackboardArtifact artifact) { @@ -1012,7 +1010,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * * @param programName The name of the program. * @param programPath The path of the program. - * @param runTimes The number of runs. + * @param runTimes The number of runs. * @param artifact The relevant blackboard artifact. */ TopProgramsResult(String programName, String programPath, Long runTimes, Date lastRun, BlackboardArtifact artifact) { diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java index 35f3b921fd..9414ffc37b 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java @@ -64,6 +64,8 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { private final EventUpdateHandler updateHandler; private final List governors; + private Runnable notifyParentClose = null; + private DataSource dataSource; /** @@ -77,7 +79,7 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { * Checks to see if artifact is from a datasource. * * @param art The artifact. - * @param ds The datasource. + * @param ds The datasource. * * @return True if in datasource; false if not or exception. */ @@ -219,7 +221,7 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { * Main constructor. * * @param governors The items governing when this panel should receive - * updates. + * updates. */ protected BaseDataSourceSummaryPanel(UpdateGovernor... governors) { this.governors = (governors == null) ? Collections.emptyList() : Arrays.asList(governors); @@ -246,6 +248,24 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { onNewDataSource(this.dataSource); } + /** + * Sends event that parent should close. + */ + protected void notifyParentClose() { + if (notifyParentClose != null) { + notifyParentClose.run(); + } + } + + /** + * Sets the listener for parent close events. + * + * @param action The action to run when parent is to close. + */ + void setParentCloseListener(Runnable action) { + notifyParentClose = action; + } + /** * @return The current data source. */ @@ -287,7 +307,7 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { * argument and data fetch components and then submits them to run. * * @param dataFetchComponents The components to be run. - * @param dataSource The data source argument. + * @param dataSource The data source argument. */ protected void fetchInformation(List> dataFetchComponents, DataSource dataSource) { if (dataSource == null || !Case.isCaseOpen()) { @@ -320,8 +340,8 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { * argument and submits them to be executed. * * @param dataFetchComponents The components to register. - * @param loadableComponents The components to set to a loading screen. - * @param dataSource The data source argument. + * @param loadableComponents The components to set to a loading screen. + * @param dataSource The data source argument. */ protected void onNewDataSource( List> dataFetchComponents, @@ -371,12 +391,11 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { * message indicating the unrun ingest module will be shown. Otherwise, the * default LoadableComponent.showDataFetchResult behavior will be used. * - * @param component The component. - * @param result The data result. + * @param component The component. + * @param result The data result. * @param factoryClass The fully qualified class name of the relevant - * factory. - * @param moduleName The name of the ingest module (i.e. 'Keyword - * Search'). + * factory. + * @param moduleName The name of the ingest module (i.e. 'Keyword Search'). */ protected void showResultWithModuleCheck(LoadableComponent> component, DataFetchResult> result, String factoryClass, String moduleName) { Predicate> hasResults = (lst) -> lst != null && !lst.isEmpty(); @@ -389,14 +408,13 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { * message indicating the unrun ingest module will be shown. Otherwise, the * default LoadableComponent.showDataFetchResult behavior will be used. * - * @param component The component. - * @param result The data result. - * @param hasResults Given the data type, will provide whether or not the - * data contains any actual results. + * @param component The component. + * @param result The data result. + * @param hasResults Given the data type, will provide whether or not the + * data contains any actual results. * @param factoryClass The fully qualified class name of the relevant - * factory. - * @param moduleName The name of the ingest module (i.e. 'Keyword - * Search'). + * factory. + * @param moduleName The name of the ingest module (i.e. 'Keyword Search'). */ protected void showResultWithModuleCheck(LoadableComponent component, DataFetchResult result, Predicate hasResults, String factoryClass, String moduleName) { diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED index 4997d067f1..517bf7a410 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED @@ -103,6 +103,7 @@ PastCasesPanel.notableFileLabel.text=Cases with Common Items That Were Tagged as PastCasesPanel.sameIdLabel.text=Past Cases with the Same Device IDs DataSourceSummaryTabbedPane.noDataSourceLabel.text=No data source has been selected. TimelinePanel.activityRangeLabel.text=Activity Range +UserActivityPanel_goToArtifact=Go to Artifact UserActivityPanel_noDataExists=No communication data exists UserActivityPanel_tab_title=User Activity UserActivityPanel_TopAccountTableModel_accountType_header=Account Type diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryDialog.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryDialog.java index 5269bdff67..b506437887 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryDialog.java @@ -40,7 +40,7 @@ import org.sleuthkit.datamodel.IngestJobInfo; * Dialog for displaying the Data Sources Summary information */ final class DataSourceSummaryDialog extends javax.swing.JDialog implements Observer { - + private static final long serialVersionUID = 1L; private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_COMPLETED); private final DataSourceBrowser dataSourcesPanel; @@ -61,6 +61,7 @@ final class DataSourceSummaryDialog extends javax.swing.JDialog implements Obser Map fileCountsMap = CaseDataSourcesSummary.getCountsOfFiles(); dataSourcesPanel = new DataSourceBrowser(usageMap, fileCountsMap); dataSourceSummaryTabbedPane = new DataSourceSummaryTabbedPane(); + dataSourceSummaryTabbedPane.setParentCloseListener(() -> DataSourceSummaryDialog.this.dispose()); initComponents(); dataSourceSummarySplitPane.setLeftComponent(dataSourcesPanel); dataSourcesPanel.addListSelectionListener((ListSelectionEvent e) -> { @@ -70,7 +71,7 @@ final class DataSourceSummaryDialog extends javax.swing.JDialog implements Obser this.repaint(); } }); - + ingestEventListener = (PropertyChangeEvent evt) -> { if (evt instanceof DataSourceAnalysisCompletedEvent) { DataSourceAnalysisCompletedEvent dsEvent = (DataSourceAnalysisCompletedEvent) evt; @@ -90,7 +91,7 @@ final class DataSourceSummaryDialog extends javax.swing.JDialog implements Obser setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); this.pack(); } - + @Override public void dispose() { IngestManager.getInstance().removeIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, ingestEventListener); @@ -104,7 +105,7 @@ final class DataSourceSummaryDialog extends javax.swing.JDialog implements Obser void enableObserver() { dataSourcesPanel.addObserver(this); } - + @Override public void update(Observable o, Object arg) { this.dispose(); @@ -169,7 +170,7 @@ final class DataSourceSummaryDialog extends javax.swing.JDialog implements Obser * source matches the dataSourceID it will select the first datasource. * * @param dataSourceID the ID of the datasource to select, null will cause - * the first datasource to be selected + * the first datasource to be selected */ void selectDataSource(Long dataSourceId) { dataSourcesPanel.selectDataSource(dataSourceId); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryTabbedPane.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryTabbedPane.java index 3670124fa2..0dde613158 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryTabbedPane.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryTabbedPane.java @@ -47,7 +47,7 @@ public class DataSourceSummaryTabbedPane extends javax.swing.JPanel { * Records of tab information (i.e. title, component, function to call on * new data source). */ - private static class DataSourceTab { + private class DataSourceTab { private final String tabTitle; private final Component component; @@ -74,8 +74,12 @@ public class DataSourceSummaryTabbedPane extends javax.swing.JPanel { * * @param tabTitle The title of the tab. * @param panel The component to be displayed in the tab. + * @param notifyParentClose Notifies parent to trigger a close. */ DataSourceTab(String tabTitle, BaseDataSourceSummaryPanel panel) { + + panel.setParentCloseListener(() -> notifyParentClose()); + this.tabTitle = tabTitle; this.component = panel; this.onDataSource = panel::setDataSource; @@ -116,20 +120,10 @@ public class DataSourceSummaryTabbedPane extends javax.swing.JPanel { private static final String TABBED_PANE = "tabbedPane"; private static final String NO_DATASOURCE_PANE = "noDataSourcePane"; + private Runnable notifyParentClose = null; private final IngestJobInfoPanel ingestHistoryPanel = new IngestJobInfoPanel(); - private final List tabs = Arrays.asList( - new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_typesTab_title(), new TypesPanel()), - new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_userActivityTab_title(), new UserActivityPanel()), - new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_analysisTab_title(), new AnalysisPanel()), - new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_recentFileTab_title(), new RecentFilesPanel()), - new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_pastCasesTab_title(), new PastCasesPanel()), - new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_timelineTab_title(), new TimelinePanel()), - // do nothing on closing - new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_ingestHistoryTab_title(), ingestHistoryPanel, ingestHistoryPanel::setDataSource, () -> { - }), - new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_detailsTab_title(), new ContainerPanel()) - ); + private final List tabs; private DataSource dataSource = null; private CardLayout cardLayout; @@ -138,10 +132,46 @@ public class DataSourceSummaryTabbedPane extends javax.swing.JPanel { * Creates new form TabPane */ public DataSourceSummaryTabbedPane() { + this.tabs = getTabs(); initComponents(); postInit(); } + /** + * Sends event that parent should close. + */ + private void notifyParentClose() { + if (notifyParentClose != null) { + notifyParentClose.run(); + } + } + + /** + * Sets the listener for parent close events. + * + * @param parentCloseAction The observer. + */ + void setParentCloseListener(Runnable parentCloseAction) { + notifyParentClose = parentCloseAction; + } + + private List getTabs() { + List tabs = Arrays.asList( + new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_typesTab_title(), new TypesPanel()), + new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_userActivityTab_title(), new UserActivityPanel()), + new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_analysisTab_title(), new AnalysisPanel()), + new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_recentFileTab_title(), new RecentFilesPanel()), + new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_pastCasesTab_title(), new PastCasesPanel()), + new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_timelineTab_title(), new TimelinePanel()), + // do nothing on closing + new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_ingestHistoryTab_title(), ingestHistoryPanel, ingestHistoryPanel::setDataSource, () -> { + }), + new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_detailsTab_title(), new ContainerPanel()) + ); + + return tabs; + } + /** * Method called right after initComponents during initialization. */ diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java index 9ed422845a..6b94c9e6b8 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java @@ -80,11 +80,17 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { private static final String ANDROID_FACTORY = "org.python.proxies.module$AndroidModuleFactory"; private static final String ANDROID_MODULE_NAME = "Android Analyzer"; - private static List getArtifactPopup(BlackboardArtifact artifact) { - return artifact == null ? null : Arrays.asList(new DefaultMenuItem(Bundle.UserActivityPanel_goToArtifact(), new ViewArtifactAction(artifact))); + private List getArtifactPopup(BlackboardArtifact artifact) { + return artifact == null ? null : Arrays.asList( + new DefaultMenuItem( + Bundle.UserActivityPanel_goToArtifact(), + () -> { + new ViewArtifactAction(artifact).run(); + notifyParentClose(); + })); } - private static List getPopup(LastAccessedArtifact record) { + private List getPopup(LastAccessedArtifact record) { return record == null ? null : getArtifactPopup(record.getArtifact()); } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/JTablePanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/JTablePanel.java index ed6e5f14ad..b3db4d1d26 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/JTablePanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/JTablePanel.java @@ -215,8 +215,8 @@ public class JTablePanel extends AbstractLoadableComponent> { // make sure there is a value at the row,col of click event. if (tableModel != null - && row > 0 && row < tableModel.getRowCount() - && col > 0 && col < tableModel.getColumnCount()) { + && row >= 0 && row < tableModel.getRowCount() + && col >= 0 && col < tableModel.getColumnCount()) { // select the row table.setRowSelectionInterval(row, row); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/ViewArtifactAction.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/ViewArtifactAction.java index 4d7f896984..b4f82e3475 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/ViewArtifactAction.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/ViewArtifactAction.java @@ -44,7 +44,7 @@ public class ViewArtifactAction implements Runnable { // Navigate to the source context artifact. if (dtc != null && artifact != null) { - dtc.viewArtifact(artifact); + dtc.viewArtifactContent(artifact); } } From 418cffa979a86424bcabf6a00ba1b5b27d55b093 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 16 Nov 2020 16:06:23 -0500 Subject: [PATCH 03/42] refactoring --- .../datamodel/AnalysisSummary.java | 81 +++++++--- .../datamodel/RecentFilesSummary.java | 65 ++++---- .../datamodel/UserActivitySummary.java | 19 +-- .../datasourcesummary/ui/AnalysisPanel.java | 36 +++-- .../ui/BaseDataSourceSummaryPanel.java | 49 ++++++ .../ui/RecentFilesPanel.java | 37 ++++- .../ui/UserActivityPanel.java | 43 ++--- .../uiutils/CellModelTableCellRenderer.java | 42 ++++- .../uiutils/JTablePanel.java | 152 ++++++++++-------- .../uiutils/ViewArtifactAction.java | 51 ------ 10 files changed, 356 insertions(+), 219 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/ViewArtifactAction.java diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java index 9d35e3d28d..55d0c0b716 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java @@ -94,7 +94,7 @@ public class AnalysisSummary implements DefaultArtifactUpdateGovernor { * @throws SleuthkitCaseProviderException * @throws TskCoreException */ - public List> getHashsetCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { + public List getHashsetCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { return getCountsData(dataSource, TYPE_SET_NAME, ARTIFACT_TYPE.TSK_HASHSET_HIT); } @@ -108,10 +108,10 @@ public class AnalysisSummary implements DefaultArtifactUpdateGovernor { * @throws SleuthkitCaseProviderException * @throws TskCoreException */ - public List> getKeywordCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { + public List getKeywordCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { return getCountsData(dataSource, TYPE_SET_NAME, ARTIFACT_TYPE.TSK_KEYWORD_HIT).stream() // make sure we have a valid set and that that set does not belong to the set of excluded items - .filter((pair) -> pair != null && pair.getKey() != null && !EXCLUDED_KEYWORD_SEARCH_ITEMS.contains(pair.getKey().toUpperCase().trim())) + .filter((record) -> record != null && record.getIdentifier()!= null && !EXCLUDED_KEYWORD_SEARCH_ITEMS.contains(record.getIdentifier().toUpperCase().trim())) .collect(Collectors.toList()); } @@ -119,33 +119,32 @@ public class AnalysisSummary implements DefaultArtifactUpdateGovernor { * Gets counts for interesting item hits. * * @param dataSource The datasource for which to identify interesting item - * hits. + * hits. * * @return The interesting item set name with the number of hits in - * descending order. + * descending order. * * @throws SleuthkitCaseProviderException * @throws TskCoreException */ - public List> getInterestingItemCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { + public List getInterestingItemCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { return getCountsData(dataSource, TYPE_SET_NAME, ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT); } /** * Get counts for the artifact of the specified type. * - * @param dataSource The datasource. - * @param keyType The attribute to use as the key type. + * @param dataSource The datasource. + * @param keyType The attribute to use as the key type. * @param artifactTypes The types of artifacts for which to query. * - * @return A list of key value pairs where the key is the attribute type - * value and the value is the count of items found. This list is - * sorted by the count descending max to min. + * @return A list of AnalysisCountRecord. This list is sorted by the count + * descending max to min. * * @throws SleuthkitCaseProviderException * @throws TskCoreException */ - private List> getCountsData(DataSource dataSource, BlackboardAttribute.Type keyType, ARTIFACT_TYPE... artifactTypes) + private List getCountsData(DataSource dataSource, BlackboardAttribute.Type keyType, ARTIFACT_TYPE... artifactTypes) throws SleuthkitCaseProviderException, TskCoreException { if (dataSource == null) { @@ -161,18 +160,64 @@ public class AnalysisSummary implements DefaultArtifactUpdateGovernor { } // group those based on the value of the attribute type that should serve as a key - Map countedKeys = artifacts.stream() + Map countedKeys = artifacts.stream() .map((art) -> { String key = DataSourceInfoUtilities.getStringOrNull(art, keyType); - return (StringUtils.isBlank(key)) ? null : key; + return (StringUtils.isBlank(key)) ? null : Pair.of(key, art); }) .filter((key) -> key != null) - .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); + .collect(Collectors.toMap( + (r) -> r.getLeft(), + (r) -> new AnalysisCountRecord(r.getLeft(), 1, r.getRight()), + (r1, r2) -> new AnalysisCountRecord(r1.getIdentifier(), r1.getCount() + r2.getCount(), r1.getArtifact()))); // sort from max to min counts - return countedKeys.entrySet().stream() - .map((e) -> Pair.of(e.getKey(), e.getValue())) - .sorted((a, b) -> -a.getValue().compareTo(b.getValue())) + return countedKeys.values().stream() + .sorted((a, b) -> -Long.compare(a.getCount(), b.getCount())) .collect(Collectors.toList()); } + + /** + * A record for an analysis item and its count. + */ + public static class AnalysisCountRecord { + + private final String identifier; + private final long count; + private final BlackboardArtifact artifact; + + /** + * Main constructor. + * + * @param identifier The identifier. + * @param count The count for how many times found. + * @param artifact The artifact. + */ + AnalysisCountRecord(String identifier, long count, BlackboardArtifact artifact) { + this.identifier = identifier; + this.count = count; + this.artifact = artifact; + } + + /** + * @return The identifier for this analysis record. + */ + public String getIdentifier() { + return identifier; + } + + /** + * @return How many times found. + */ + public long getCount() { + return count; + } + + /** + * @return The relevant artifact. + */ + public BlackboardArtifact getArtifact() { + return artifact; + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummary.java index 6c4601af88..c46db82de6 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummary.java @@ -98,11 +98,11 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { * TSK_RECENT_OBJECT artifact. * * @param dataSource The data source to query. - * @param maxCount The maximum number of results to return, pass 0 to get - * a list of all results. + * @param maxCount The maximum number of results to return, pass 0 to get a + * list of all results. * * @return A list RecentFileDetails representing the most recently opened - * documents or an empty list if none were found. + * documents or an empty list if none were found. * * @throws SleuthkitCaseProviderException * @throws TskCoreException @@ -137,7 +137,7 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { } if (accessedTime != null && accessedTime != 0) { - fileDetails.add(new RecentFileDetails(path, accessedTime)); + fileDetails.add(new RecentFileDetails(artifact, path, accessedTime)); } } @@ -149,11 +149,11 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { * artifact TSK_DATETIME_ACCESSED attribute. * * @param dataSource Data source to query. - * @param maxCount Maximum number of results to return, passing 0 will - * return all results. + * @param maxCount Maximum number of results to return, passing 0 will + * return all results. * * @return A list of RecentFileDetails objects or empty list if none were - * found. + * found. * * @throws TskCoreException * @throws SleuthkitCaseProviderException @@ -190,7 +190,7 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { } } if (accessedTime != null && accessedTime != 0L) { - fileDetails.add(new RecentDownloadDetails(path, accessedTime, domain)); + fileDetails.add(new RecentDownloadDetails(artifact, path, accessedTime, domain)); } } @@ -201,8 +201,8 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { * Returns a list of the most recent message attachments. * * @param dataSource Data source to query. - * @param maxCount Maximum number of results to return, passing 0 will - * return all results. + * @param maxCount Maximum number of results to return, passing 0 will + * return all results. * * @return A list of RecentFileDetails of the most recent attachments. * @@ -227,7 +227,7 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { * @param dataSource Data source to query. * * @return Returns a SortedMap of details objects returned in descending - * order. + * order. * * @throws SleuthkitCaseProviderException * @throws TskCoreException @@ -272,7 +272,7 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { list = new ArrayList<>(); sortedMap.put(date, list); } - RecentAttachmentDetails details = new RecentAttachmentDetails(path, date, sender); + RecentAttachmentDetails details = new RecentAttachmentDetails(messageArtifact, path, date, sender); if (!list.contains(details)) { list.add(details); } @@ -288,10 +288,10 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { * size. * * @param sortedMap A Map of attachment details sorted by date. - * @param maxCount Maximum number of values to return. + * @param maxCount Maximum number of values to return. * * @return A list of the details of the most recent attachments or empty - * list if none where found. + * list if none where found. */ private List createListFromMap(SortedMap> sortedMap, int maxCount) { List fileList = new ArrayList<>(); @@ -322,7 +322,7 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { * Is the given artifact a message. * * @param nodeArtifact An artifact that might be a message. Must not be - * null. + * null. * * @return True if the given artifact is a message artifact */ @@ -339,14 +339,17 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { private final String path; private final long date; + private final BlackboardArtifact artifact; /** * Constructor for files with just a path and date. * + * @param artifact The relevant artifact. * @param path File path. * @param date File access date\time in seconds with java epoch */ - RecentFileDetails(String path, long date) { + RecentFileDetails(BlackboardArtifact artifact, String path, long date) { + this.artifact = artifact; this.path = path; this.date = date; } @@ -379,6 +382,12 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { return path; } + /** + * @return The pertinent artifact for this recent file hit. + */ + public BlackboardArtifact getArtifact() { + return artifact; + } } /** @@ -391,12 +400,13 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { /** * Constructor for files with just a path and date. * - * @param path File path. - * @param date File access date\time in seconds with java epoch. + * @param artifact The relevant artifact. + * @param path File path. + * @param date File access date\time in seconds with java epoch. * @param webDomain The webdomain from which the file was downloaded. */ - RecentDownloadDetails(String path, long date, String webDomain) { - super(path, date); + RecentDownloadDetails(BlackboardArtifact artifact, String path, long date, String webDomain) { + super(artifact, path, date); this.webDomain = webDomain; } @@ -404,7 +414,7 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { * Returns the web domain. * * @return The web domain or empty string if not available or - * applicable. + * applicable. */ public String getWebDomain() { return webDomain; @@ -422,13 +432,14 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { * Constructor for recent download files which have a path, date and * domain value. * - * @param path File path. - * @param date File crtime. + * @param artifact The relevant artifact. + * @param path File path. + * @param date File crtime. * @param sender The sender of the message from which the file was - * attached. + * attached. */ - RecentAttachmentDetails(String path, long date, String sender) { - super(path, date); + RecentAttachmentDetails(BlackboardArtifact artifact, String path, long date, String sender) { + super(artifact, path, date); this.sender = sender; } @@ -436,7 +447,7 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { * Return the sender of the attached file. * * @return The sender of the attached file or empty string if not - * available. + * available. */ public String getSender() { return sender; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java index 293dd3c3fc..d05a680a66 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java @@ -508,7 +508,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { String type = DataSourceInfoUtilities.getStringOrNull(artifact, TYPE_MESSAGE_TYPE); Date date = DataSourceInfoUtilities.getDateOrNull(artifact, TYPE_DATETIME); return (StringUtils.isNotBlank(type) && date != null) - ? new TopAccountResult(type, date) + ? new TopAccountResult(type, date, artifact) : null; } @@ -536,7 +536,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { } return (StringUtils.isNotBlank(type) && latestDate != null) - ? new TopAccountResult(type, latestDate) + ? new TopAccountResult(type, latestDate, artifact) : null; } @@ -928,20 +928,20 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * A record of an account and the last time it was used determined by * messages. */ - public static class TopAccountResult { + public static class TopAccountResult extends LastAccessedArtifact { private final String accountType; - private final Date lastAccess; /** * Main constructor. * * @param accountType The account type. * @param lastAccess The date the account was last accessed. + * @param artifact The artifact indicating last access. */ - public TopAccountResult(String accountType, Date lastAccess) { + public TopAccountResult(String accountType, Date lastAccess, BlackboardArtifact artifact) { + super(lastAccess, artifact); this.accountType = accountType; - this.lastAccess = lastAccess; } /** @@ -950,13 +950,6 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { public String getAccountType() { return accountType; } - - /** - * @return The date the account was last accessed. - */ - public Date getLastAccessed() { - return lastAccess; - } } /** diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java index 34dfa97a13..8721cb0ef0 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java @@ -21,10 +21,11 @@ package org.sleuthkit.autopsy.datasourcesummary.ui; import java.util.Arrays; import java.util.List; import java.util.function.Function; -import org.apache.commons.lang3.tuple.Pair; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.datasourcesummary.datamodel.AnalysisSummary; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.AnalysisSummary.AnalysisCountRecord; import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.DefaultCellModel; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.MenuItem; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel; @@ -58,30 +59,30 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { /** * Default Column definitions for each table */ - private static final List>> DEFAULT_COLUMNS = Arrays.asList( + private final List> DEFAULT_COLUMNS = Arrays.asList( new ColumnModel<>( Bundle.AnalysisPanel_keyColumn_title(), - (pair) -> new DefaultCellModel(pair.getKey()), + (r) -> new DefaultCellModel(r.getIdentifier()).setPopupMenu(getPopup(r)), 300 ), new ColumnModel<>( Bundle.AnalysisPanel_countColumn_title(), - (pair) -> new DefaultCellModel(String.valueOf(pair.getValue())), + (r) -> new DefaultCellModel(String.valueOf(Long.toString(r.getCount()))).setPopupMenu(getPopup(r)), 100 ) ); - private static final Function, String> DEFAULT_KEY_PROVIDER = (pair) -> pair.getKey(); + private final Function DEFAULT_KEY_PROVIDER = (pair) -> pair.getIdentifier(); - private final JTablePanel> hashsetHitsTable + private final JTablePanel hashsetHitsTable = JTablePanel.getJTablePanel(DEFAULT_COLUMNS) .setKeyFunction(DEFAULT_KEY_PROVIDER); - private final JTablePanel> keywordHitsTable + private final JTablePanel keywordHitsTable = JTablePanel.getJTablePanel(DEFAULT_COLUMNS) .setKeyFunction(DEFAULT_KEY_PROVIDER); - private final JTablePanel> interestingItemsTable + private final JTablePanel interestingItemsTable = JTablePanel.getJTablePanel(DEFAULT_COLUMNS) .setKeyFunction(DEFAULT_KEY_PROVIDER); @@ -90,9 +91,8 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { keywordHitsTable, interestingItemsTable ); - + private final IngestRunningLabel ingestRunningLabel = new IngestRunningLabel(); - /** * All of the components necessary for data fetch swing workers to load data @@ -129,14 +129,24 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { initComponents(); } - + /** + * Takes a base class of AnalysisCountRecord and provides the pertinent menu + * items. going to artifact. + * + * @param record The AnalysisCountRecord instance. + * @return The menu items list containing one action or navigating to the + * appropriate artifact and closing the data source summary dialog if open. + */ + private List getPopup(AnalysisCountRecord record) { + return record == null ? null : navigateToArtifactPopup(record.getArtifact()); + } + @Override public void close() { ingestRunningLabel.unregister(); super.close(); } - - + @Override protected void fetchInformation(DataSource dataSource) { fetchInformation(dataFetchComponents, dataSource); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java index 9414ffc37b..39af255c64 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java @@ -33,6 +33,7 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datasourcesummary.datamodel.IngestModuleCheckUtil; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult.ResultType; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; @@ -41,6 +42,7 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.EventUpdateHandler; import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableComponent; import org.sleuthkit.autopsy.datasourcesummary.uiutils.SwingWorkerSequentialExecutor; import org.sleuthkit.autopsy.datasourcesummary.uiutils.UpdateGovernor; +import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; import org.sleuthkit.autopsy.ingest.IngestManager.IngestJobEvent; import org.sleuthkit.autopsy.ingest.ModuleContentEvent; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; @@ -53,6 +55,7 @@ import org.sleuthkit.datamodel.TskCoreException; /** * Base class from which other tabs in data source summary derive. */ +@Messages({"UserActivityPanel_goToArtifact=Go to Artifact"}) abstract class BaseDataSourceSummaryPanel extends JPanel { private static final long serialVersionUID = 1L; @@ -229,6 +232,52 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { this.updateHandler.register(); } + /** + * Given the relevant artifact, navigates to the artifact in the tree and + * closes data source summary dialog if open. + * + * @param artifact The artifact. + * @return The menu item list for a go to artifact menu item. + */ + protected List navigateToArtifactPopup(BlackboardArtifact artifact) { + return artifact == null ? null : Arrays.asList( + new CellModelTableCellRenderer.DefaultMenuItem( + Bundle.UserActivityPanel_goToArtifact(), + () -> { + final DirectoryTreeTopComponent dtc = DirectoryTreeTopComponent.findInstance(); + + // Navigate to the source context artifact. + if (dtc != null && artifact != null) { + dtc.viewArtifact(artifact); + } + + notifyParentClose(); + })); + } + + /** + * Given the relevant artifact, navigates to the artifact's content in the + * tree and closes data source summary dialog if open. + * + * @param artifact The artifact. + * @return The menu item list for a go to artifact menu item. + */ + protected List navigateToArtifactContentPopup(BlackboardArtifact artifact) { + return artifact == null ? null : Arrays.asList( + new CellModelTableCellRenderer.DefaultMenuItem( + Bundle.UserActivityPanel_goToArtifact(), + () -> { + final DirectoryTreeTopComponent dtc = DirectoryTreeTopComponent.findInstance(); + + // Navigate to the source context artifact. + if (dtc != null && artifact != null) { + dtc.viewArtifactContent(artifact); + } + + notifyParentClose(); + })); + } + /** * Closes listeners and resources. */ diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java index 1b675032d0..f4fca025f5 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java @@ -28,6 +28,7 @@ import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.Rece import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentDownloadDetails; import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentFileDetails; import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.DefaultCellModel; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.MenuItem; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel; @@ -77,6 +78,18 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { initalizeTables(); } + /** + * Takes a base class of RecentFileDetails and provides the pertinent menu + * items. going to artifact. + * + * @param record The RecentFileDetails instance. + * @return The menu items list containing one action or navigating to the + * appropriate artifact and closing the data source summary dialog if open. + */ + private List getPopup(RecentFileDetails record) { + return record == null ? null : navigateToArtifactPopup(record.getArtifact()); + } + @Override protected void fetchInformation(DataSource dataSource) { fetchInformation(dataFetchComponents, dataSource); @@ -113,11 +126,13 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { List> list = Arrays.asList( new ColumnModel<>(Bundle.RecentFilePanel_col_header_path(), (prog) -> { - return new DefaultCellModel(prog.getPath()); + return new DefaultCellModel(prog.getPath()) + .setPopupMenu(getPopup(prog)); }, 250), new ColumnModel<>(Bundle.RecentFilesPanel_col_head_date(), (prog) -> { - return new DefaultCellModel(prog.getDateAsString()); + return new DefaultCellModel(prog.getDateAsString()) + .setPopupMenu(getPopup(prog)); }, 80)); ListTableModel tableModel = JTablePanel.getTableModel(list); @@ -148,15 +163,18 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { List> list = Arrays.asList( new ColumnModel<>(Bundle.RecentFilePanel_col_header_domain(), (prog) -> { - return new DefaultCellModel(prog.getWebDomain()); + return new DefaultCellModel(prog.getWebDomain()) + .setPopupMenu(getPopup(prog)); }, 100), new ColumnModel<>(Bundle.RecentFilePanel_col_header_path(), (prog) -> { - return new DefaultCellModel(prog.getPath()); + return new DefaultCellModel(prog.getPath()) + .setPopupMenu(getPopup(prog)); }, 250), new ColumnModel<>(Bundle.RecentFilesPanel_col_head_date(), (prog) -> { - return new DefaultCellModel(prog.getDateAsString()); + return new DefaultCellModel(prog.getDateAsString()) + .setPopupMenu(getPopup(prog)); }, 80)); ListTableModel tableModel = JTablePanel.getTableModel(list); @@ -187,15 +205,18 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { List> list = Arrays.asList( new ColumnModel<>(Bundle.RecentFilePanel_col_header_path(), (prog) -> { - return new DefaultCellModel(prog.getPath()); + return new DefaultCellModel(prog.getPath()) + .setPopupMenu(getPopup(prog)); }, 250), new ColumnModel<>(Bundle.RecentFilesPanel_col_head_date(), (prog) -> { - return new DefaultCellModel(prog.getDateAsString()); + return new DefaultCellModel(prog.getDateAsString()) + .setPopupMenu(getPopup(prog)); }, 80), new ColumnModel<>(Bundle.RecentFilePanel_col_header_sender(), (prog) -> { - return new DefaultCellModel(prog.getSender()); + return new DefaultCellModel(prog.getSender()) + .setPopupMenu(getPopup(prog)); }, 150)); ListTableModel tableModel = JTablePanel.getTableModel(list); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java index 6b94c9e6b8..ad9d7a2db2 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java @@ -36,14 +36,11 @@ import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.Top import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopDomainsResult; import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopProgramsResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.DefaultCellModel; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.DefaultMenuItem; import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.MenuItem; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel.ColumnModel; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ViewArtifactAction; -import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.DataSource; /** @@ -66,8 +63,7 @@ import org.sleuthkit.datamodel.DataSource; "UserActivityPanel_TopDeviceAttachedTableModel_dateAccessed_header=Last Accessed", "UserActivityPanel_TopAccountTableModel_accountType_header=Account Type", "UserActivityPanel_TopAccountTableModel_lastAccess_header=Last Accessed", - "UserActivityPanel_noDataExists=No communication data exists", - "UserActivityPanel_goToArtifact=Go to Artifact"}) + "UserActivityPanel_noDataExists=No communication data exists"}) public class UserActivityPanel extends BaseDataSourceSummaryPanel { private static final long serialVersionUID = 1L; @@ -80,20 +76,6 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { private static final String ANDROID_FACTORY = "org.python.proxies.module$AndroidModuleFactory"; private static final String ANDROID_MODULE_NAME = "Android Analyzer"; - private List getArtifactPopup(BlackboardArtifact artifact) { - return artifact == null ? null : Arrays.asList( - new DefaultMenuItem( - Bundle.UserActivityPanel_goToArtifact(), - () -> { - new ViewArtifactAction(artifact).run(); - notifyParentClose(); - })); - } - - private List getPopup(LastAccessedArtifact record) { - return record == null ? null : getArtifactPopup(record.getArtifact()); - } - /** * Gets a string formatted date or returns empty string if the date is null. * @@ -249,13 +231,19 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { // account type column new ColumnModel( Bundle.UserActivityPanel_TopAccountTableModel_accountType_header(), - (account) -> new DefaultCellModel(account.getAccountType()), + (account) -> { + return new DefaultCellModel(account.getAccountType()) + .setPopupMenu(getPopup(account)); + }, 250 ), // last accessed new ColumnModel<>( Bundle.UserActivityPanel_TopAccountTableModel_lastAccess_header(), - (account) -> new DefaultCellModel(getFormatted(account.getLastAccessed())), + (account) -> { + return new DefaultCellModel(getFormatted(account.getLastAccessed())) + .setPopupMenu(getPopup(account)); + }, 150 ) )) @@ -338,6 +326,19 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { initComponents(); } + /** + * Takes a base class of LastAccessedArtifact and provides the pertinent + * menu items. going to artifact. + * + * @param record The LastAccessedArtifact instance. + * @param navigateToArtifact Navigate right tot the artifact. + * @return The menu items list containing one action or navigating to the + * appropriate artifact and closing the data source summary dialog if open. + */ + private List getPopup(LastAccessedArtifact record) { + return record == null ? null : navigateToArtifactPopup(record.getArtifact()); + } + /** * Queries DataSourceTopProgramsSummary instance for short folder name. * diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/CellModelTableCellRenderer.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/CellModelTableCellRenderer.java index 02d6d6b34b..8ae72c89c5 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/CellModelTableCellRenderer.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/CellModelTableCellRenderer.java @@ -20,15 +20,22 @@ package org.sleuthkit.autopsy.datasourcesummary.uiutils; import java.awt.Component; import java.awt.Insets; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.swing.BorderFactory; import javax.swing.JLabel; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; import javax.swing.JTable; import javax.swing.border.Border; import javax.swing.table.DefaultTableCellRenderer; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel.CellMouseEvent; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel.CellMouseListener; /** * A Table cell renderer that renders a cell of a table based off of the @@ -93,6 +100,7 @@ public class CellModelTableCellRenderer extends DefaultTableCellRenderer { /** * Main constructor. + * * @param title The title for the menu item. * @param action The action should the menu item be clicked. */ @@ -222,11 +230,12 @@ public class CellModelTableCellRenderer extends DefaultTableCellRenderer { @Override public List getPopupMenu() { - return popupMenu == null ? null : Collections.unmodifiableList(popupMenu); + return popupMenu == null ? null : Collections.unmodifiableList(popupMenu); } /** * Sets the list of items for a popup menu + * * @param popupMenu * @return As a utility, returns this. */ @@ -234,8 +243,6 @@ public class CellModelTableCellRenderer extends DefaultTableCellRenderer { this.popupMenu = popupMenu == null ? null : new ArrayList<>(popupMenu); return this; } - - @Override public String toString() { @@ -302,4 +309,33 @@ public class CellModelTableCellRenderer extends DefaultTableCellRenderer { return defaultCell; } + + private static final CellMouseListener DEFAULT_CELL_MOUSE_LISTENER = new CellMouseListener() { + + @Override + public void mouseClicked(CellMouseEvent cellEvent) { + if (cellEvent.getCellValue() instanceof CellModel) { + CellModel cellModel = (CellModel) cellEvent.getCellValue(); + List menuItems = cellModel.getPopupMenu(); + + // if there are menu items, show a popup menu for + // this item with all the menu items. + if (CollectionUtils.isNotEmpty(menuItems)) { + final JPopupMenu popupMenu = new JPopupMenu(); + for (MenuItem mItem : menuItems) { + JMenuItem jMenuItem = new JMenuItem(mItem.getTitle()); + if (mItem.getAction() != null) { + jMenuItem.addActionListener((evt) -> mItem.getAction().run()); + } + popupMenu.add(jMenuItem); + } + popupMenu.show(cellEvent.getTable(), cellEvent.getMouseEvent().getX(), cellEvent.getMouseEvent().getY()); + } + } + } + }; + + public static CellMouseListener getMouseListener() { + return DEFAULT_CELL_MOUSE_LISTENER; + } } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/JTablePanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/JTablePanel.java index b3db4d1d26..ec055a42b9 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/JTablePanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/JTablePanel.java @@ -22,24 +22,19 @@ import java.awt.BorderLayout; import java.awt.Graphics; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; import java.util.Collections; import java.util.List; import java.util.function.Function; import java.util.stream.Collectors; import javax.swing.JComponent; import javax.swing.JLayer; -import javax.swing.JMenuItem; -import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.plaf.LayerUI; import javax.swing.table.DefaultTableColumnModel; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; -import org.apache.commons.collections.CollectionUtils; import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.CellModel; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.MenuItem; /** * A table that displays a list of items and also can display messages for @@ -47,6 +42,55 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRendere */ public class JTablePanel extends AbstractLoadableComponent> { + public static class CellMouseEvent { + private final MouseEvent e; + private final JTable table; + private final int row; + private final int col; + private final Object cellValue; + + public CellMouseEvent(MouseEvent e, JTable table, int row, int col, Object cellValue) { + this.e = e; + this.table = table; + this.row = row; + this.col = col; + this.cellValue = cellValue; + } + + public MouseEvent getMouseEvent() { + return e; + } + + public JTable getTable() { + return table; + } + + public int getRow() { + return row; + } + + public int getCol() { + return col; + } + + public Object getCellValue() { + return cellValue; + } + } + + /** + * Handles mouse events for cells in the table. + */ + public interface CellMouseListener { + + /** + * Handles mouse events at a cell level for the table. + * + * @param e The event containing information about the cell, the mouse event, and the table. + */ + void mouseClicked(CellMouseEvent e); + } + /** * JTables don't allow displaying messages. So this LayerUI is used to * display the contents of a child JLabel. Inspired by TableWaitLayerTest @@ -194,62 +238,6 @@ public class JTablePanel extends AbstractLoadableComponent> { return new DefaultListTableModel(columnRenderers); } - /** - * Sets up a table mouse listener to trigger a popup menu if the cell - * clicked has a popup menu. - * - * @param tablePanel Th JTablePanel instance. - */ - private static void setPopupListener(final JTablePanel tablePanel) { - final JTable table = tablePanel.table; - final ListTableModel tableModel = tablePanel.tableModel; - - // add mouse listener to table for popup menu item click - tablePanel.table.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - // make sure click event isn't primary button and table is present - if (e.getButton() != MouseEvent.BUTTON1 && tablePanel.table != null) { - int row = table.rowAtPoint(e.getPoint()); - int col = table.columnAtPoint(e.getPoint()); - - // make sure there is a value at the row,col of click event. - if (tableModel != null - && row >= 0 && row < tableModel.getRowCount() - && col >= 0 && col < tableModel.getColumnCount()) { - - // select the row - table.setRowSelectionInterval(row, row); - - Object cellModelObj = tableModel.getValueAt(row, col); - // if the object at that cell is a cell model object. - if (cellModelObj instanceof CellModel) { - CellModel cellModel = (CellModel) cellModelObj; - List menuItems = cellModel.getPopupMenu(); - - // if there are menu items, show a popup menu for - // this item with all the menu items. - if (CollectionUtils.isNotEmpty(menuItems)) { - final JPopupMenu popupMenu = new JPopupMenu(); - for (MenuItem mItem : menuItems) { - JMenuItem jMenuItem = new JMenuItem(mItem.getTitle()); - if (mItem.getAction() != null) { - jMenuItem.addActionListener((evt) -> mItem.getAction().run()); - } - popupMenu.add(jMenuItem); - } - popupMenu.show(table, e.getX(), e.getY()); - } - } - - } - - } - } - - }); - } - /** * Generates a JTablePanel corresponding to the provided column definitions * where 'T' is the object representing each row. @@ -260,17 +248,19 @@ public class JTablePanel extends AbstractLoadableComponent> { */ public static JTablePanel getJTablePanel(List> columns) { ListTableModel tableModel = getTableModel(columns); - JTablePanel resultTable = new JTablePanel<>(tableModel); - setPopupListener(resultTable); - return resultTable.setColumnModel(getTableColumnModel(columns)); + JTablePanel resultTable = new JTablePanel<>(tableModel) + .setColumnModel(getTableColumnModel(columns)) + .setCellListener(CellModelTableCellRenderer.getMouseListener()); + + return resultTable; } private JScrollPane tableScrollPane; private Overlay overlayLayer; private ListTableModel tableModel; private JTable table; + private CellMouseListener cellListener = null; private Function keyFunction = (rowItem) -> rowItem; - private MouseListener tableMouseListener = null; /** * Panel constructor. @@ -287,6 +277,26 @@ public class JTablePanel extends AbstractLoadableComponent> { */ public JTablePanel() { initComponents(); + this.table.addMouseListener(new MouseAdapter() { + + @Override + public void mouseClicked(MouseEvent e) { + // make sure click event isn't primary button and table is present + if (cellListener != null) { + int row = table.rowAtPoint(e.getPoint()); + int col = table.columnAtPoint(e.getPoint()); + + // make sure there is a value at the row,col of click event. + if (tableModel != null + && row >= 0 && row < tableModel.getRowCount() + && col >= 0 && col < tableModel.getColumnCount()) { + + Object cellValue = tableModel.getValueAt(row, col); + cellListener.mouseClicked(new CellMouseEvent(e, table, row, col, cellValue)); + } + } + } + }); } /** @@ -307,6 +317,18 @@ public class JTablePanel extends AbstractLoadableComponent> { return this; } + + public CellMouseListener getCellListener() { + return cellListener; + } + + public JTablePanel setCellListener(CellMouseListener cellListener) { + this.cellListener = cellListener; + return this; + } + + + /** * @return The underlying JTable's column model. */ diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/ViewArtifactAction.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/ViewArtifactAction.java deleted file mode 100644 index b4f82e3475..0000000000 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/ViewArtifactAction.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2020 Basis Technology Corp. - * Contact: carrier sleuthkit 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.datasourcesummary.uiutils; - -import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; -import org.sleuthkit.datamodel.BlackboardArtifact; - -/** - * Action that navigates to an artifact in a tree. - */ -public class ViewArtifactAction implements Runnable { - - private final BlackboardArtifact artifact; - - /** - * Main constructor for this action. - * - * @param artifact The artifact that will be displayed in tree - * DirectoryTreeTopComponent. - */ - public ViewArtifactAction(BlackboardArtifact artifact) { - this.artifact = artifact; - } - - @Override - public void run() { - final DirectoryTreeTopComponent dtc = DirectoryTreeTopComponent.findInstance(); - - // Navigate to the source context artifact. - if (dtc != null && artifact != null) { - dtc.viewArtifactContent(artifact); - } - } - -} From b7ba4d64a012cbb08b7c44effc72ee488bd24931 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 16 Nov 2020 16:09:47 -0500 Subject: [PATCH 04/42] quick fix --- .../datasourcesummary/uiutils/CellModelTableCellRenderer.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/CellModelTableCellRenderer.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/CellModelTableCellRenderer.java index 8ae72c89c5..3511101da4 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/CellModelTableCellRenderer.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/CellModelTableCellRenderer.java @@ -314,7 +314,8 @@ public class CellModelTableCellRenderer extends DefaultTableCellRenderer { @Override public void mouseClicked(CellMouseEvent cellEvent) { - if (cellEvent.getCellValue() instanceof CellModel) { + if (cellEvent.getCellValue() instanceof CellModel && cellEvent.getMouseEvent().getButton() != MouseEvent.BUTTON1) { + cellEvent.getTable().setRowSelectionInterval(cellEvent.getRow(), cellEvent.getRow()); CellModel cellModel = (CellModel) cellEvent.getCellValue(); List menuItems = cellModel.getPopupMenu(); From 73adb2244195d9a0d297780fe6afd3b6407dbe7a Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 17 Nov 2020 11:07:36 -0500 Subject: [PATCH 05/42] get timeline click listener working --- .../datamodel/TimelineSummary.java | 45 +++++++++++-------- .../datasourcesummary/ui/AnalysisPanel.java | 2 +- .../ui/BaseDataSourceSummaryPanel.java | 9 ++-- .../ui/Bundle.properties-MERGED | 1 + .../ui/RecentFilesPanel.java | 2 +- .../datasourcesummary/ui/TimelinePanel.java | 43 ++++++++++++++++++ .../ui/UserActivityPanel.java | 2 +- .../uiutils/BarChartPanel.java | 39 ++++++++++++++++ 8 files changed, 117 insertions(+), 26 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummary.java index 1d634211be..c892c7eec8 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummary.java @@ -44,13 +44,24 @@ import org.sleuthkit.datamodel.TimelineFilter.RootFilter; import org.sleuthkit.datamodel.TimelineManager; import org.sleuthkit.datamodel.TskCoreException; import java.util.function.Supplier; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.core.UserPreferences; +import org.sleuthkit.autopsy.timeline.TimeLineController; +import org.sleuthkit.autopsy.timeline.TimeLineModule; +import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.FilterState; +import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.RootFilterState; +import org.sleuthkit.autopsy.timeline.utils.FilterUtils; /** * Provides data source summary information pertaining to Timeline data. */ public class TimelineSummary implements DefaultUpdateGovernor { + + public interface DataSourceFilterFunction { + RootFilter apply(DataSource dataSource) throws NoCurrentCaseException, TskCoreException; + } + private static final long DAY_SECS = 24 * 60 * 60; private static final Set INGEST_JOB_EVENTS = new HashSet<>( Arrays.asList(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED)); @@ -64,12 +75,15 @@ public class TimelineSummary implements DefaultUpdateGovernor { private final SleuthkitCaseProvider caseProvider; private final Supplier timeZoneProvider; - + private final DataSourceFilterFunction filterFunction; + /** * Default constructor. */ public TimelineSummary() { - this(SleuthkitCaseProvider.DEFAULT, () -> TimeZone.getTimeZone(UserPreferences.getTimeZoneForDisplays())); + this(SleuthkitCaseProvider.DEFAULT, + () -> TimeZone.getTimeZone(UserPreferences.getTimeZoneForDisplays()), + (ds) -> TimelineDataSourceUtils.getInstance().getDataSourceFilter(ds)); } /** @@ -77,10 +91,12 @@ public class TimelineSummary implements DefaultUpdateGovernor { * * @param caseProvider SleuthkitCaseProvider provider, cannot be null. * @param timeZoneProvider The timezone provider, cannot be null. + * @param defaulteStateSupplier Provides the default root filter */ - public TimelineSummary(SleuthkitCaseProvider caseProvider, Supplier timeZoneProvider) { + public TimelineSummary(SleuthkitCaseProvider caseProvider, Supplier timeZoneProvider, DataSourceFilterFunction filterFunction) { this.caseProvider = caseProvider; this.timeZoneProvider = timeZoneProvider; + this.filterFunction = filterFunction; } @Override @@ -113,8 +129,9 @@ public class TimelineSummary implements DefaultUpdateGovernor { * @return The retrieved data. * @throws SleuthkitCaseProviderException * @throws TskCoreException + * @throws NoCurrentCaseException */ - public TimelineSummaryData getData(DataSource dataSource, int recentDaysNum) throws SleuthkitCaseProviderException, TskCoreException { + public TimelineSummaryData getData(DataSource dataSource, int recentDaysNum) throws SleuthkitCaseProviderException, TskCoreException, NoCurrentCaseException { TimeZone timeZone = this.timeZoneProvider.get(); TimelineManager timelineManager = this.caseProvider.get().getTimelineManager(); @@ -181,25 +198,15 @@ public class TimelineSummary implements DefaultUpdateGovernor { * belongs. * @return A Map mapping days from epoch to the activity for that day. * @throws TskCoreException + * @throws NoCurrentCaseException */ - private Map getTimelineEventsByDay(DataSource dataSource, TimelineManager timelineManager, TimeZone timeZone) throws TskCoreException { - - DataSourcesFilter dataSourceFilter = new DataSourcesFilter(); - dataSourceFilter.addSubFilter(new TimelineFilter.DataSourceFilter(dataSource.getName(), dataSource.getId())); - - RootFilter dataSourceRootFilter = new RootFilter( - null, - null, - null, - null, - null, - dataSourceFilter, - null, - Collections.emptySet()); + private Map getTimelineEventsByDay(DataSource dataSource, TimelineManager timelineManager, TimeZone timeZone) + throws TskCoreException, NoCurrentCaseException { + RootFilter rootFilter = this.filterFunction.apply(dataSource); // get events for data source long curRunTime = System.currentTimeMillis(); - List events = timelineManager.getEvents(new Interval(1, curRunTime), dataSourceRootFilter); + List events = timelineManager.getEvents(new Interval(1, curRunTime), rootFilter); // get counts of events per day (left is file system events, right is everything else) Map dateCounts = new HashMap<>(); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java index 8721cb0ef0..d0f14f390d 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java @@ -138,7 +138,7 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { * appropriate artifact and closing the data source summary dialog if open. */ private List getPopup(AnalysisCountRecord record) { - return record == null ? null : navigateToArtifactPopup(record.getArtifact()); + return record == null ? null : getNavigateToArtifactPopup(record.getArtifact()); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java index 39af255c64..d4ff6ef081 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java @@ -55,7 +55,8 @@ import org.sleuthkit.datamodel.TskCoreException; /** * Base class from which other tabs in data source summary derive. */ -@Messages({"UserActivityPanel_goToArtifact=Go to Artifact"}) +@Messages({"UserActivityPanel_goToArtifact=Go to Artifact", + "UserActivityPanel_goToArtifactContent=Go to File"}) abstract class BaseDataSourceSummaryPanel extends JPanel { private static final long serialVersionUID = 1L; @@ -239,7 +240,7 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { * @param artifact The artifact. * @return The menu item list for a go to artifact menu item. */ - protected List navigateToArtifactPopup(BlackboardArtifact artifact) { + protected List getNavigateToArtifactPopup(BlackboardArtifact artifact) { return artifact == null ? null : Arrays.asList( new CellModelTableCellRenderer.DefaultMenuItem( Bundle.UserActivityPanel_goToArtifact(), @@ -262,10 +263,10 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { * @param artifact The artifact. * @return The menu item list for a go to artifact menu item. */ - protected List navigateToArtifactContentPopup(BlackboardArtifact artifact) { + protected List getNavigateToArtifactContentPopup(BlackboardArtifact artifact) { return artifact == null ? null : Arrays.asList( new CellModelTableCellRenderer.DefaultMenuItem( - Bundle.UserActivityPanel_goToArtifact(), + Bundle.UserActivityPanel_goToArtifactContent(), () -> { final DirectoryTreeTopComponent dtc = DirectoryTreeTopComponent.findInstance(); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED index 517bf7a410..4902a46385 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED @@ -104,6 +104,7 @@ PastCasesPanel.sameIdLabel.text=Past Cases with the Same Device IDs DataSourceSummaryTabbedPane.noDataSourceLabel.text=No data source has been selected. TimelinePanel.activityRangeLabel.text=Activity Range UserActivityPanel_goToArtifact=Go to Artifact +UserActivityPanel_goToArtifactContent=Go to File UserActivityPanel_noDataExists=No communication data exists UserActivityPanel_tab_title=User Activity UserActivityPanel_TopAccountTableModel_accountType_header=Account Type diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java index f4fca025f5..fc87d54d2c 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java @@ -87,7 +87,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { * appropriate artifact and closing the data source summary dialog if open. */ private List getPopup(RecentFileDetails record) { - return record == null ? null : navigateToArtifactPopup(record.getArtifact()); + return record == null ? null : getNavigateToArtifactContentPopup(record.getArtifact()); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java index 87f170ccab..2bc9eff126 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java @@ -19,15 +19,23 @@ package org.sleuthkit.autopsy.datasourcesummary.ui; import java.awt.Color; +import java.awt.Cursor; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Locale; +import java.util.logging.Level; import org.apache.commons.collections.CollectionUtils; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineDataSourceUtils; import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.DailyActivityAmount; import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.TimelineSummaryData; @@ -41,7 +49,17 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetch import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableComponent; import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableLabel; +import org.sleuthkit.autopsy.timeline.OpenTimelineAction; +import org.sleuthkit.autopsy.timeline.TimeLineController; +import org.sleuthkit.autopsy.timeline.TimeLineModule; +import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.FilterState; +import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.RootFilterState; +import org.sleuthkit.autopsy.timeline.utils.FilterUtils; import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.TimelineEventType; +import org.sleuthkit.datamodel.TimelineFilter; +import org.sleuthkit.datamodel.TimelineFilter.DataSourceFilter; +import org.sleuthkit.datamodel.TskCoreException; /** * A tab shown in data source summary displaying information about a data @@ -55,6 +73,7 @@ import org.sleuthkit.datamodel.DataSource; "TimlinePanel_last30DaysChart_artifactEvts_title=Artifact Events",}) public class TimelinePanel extends BaseDataSourceSummaryPanel { + private static final Logger logger = Logger.getLogger(TimelinePanel.class.getName()); private static final long serialVersionUID = 1L; private static final DateFormat EARLIEST_LATEST_FORMAT = getUtcFormat("MMM d, yyyy"); private static final DateFormat CHART_FORMAT = getUtcFormat("MMM d"); @@ -75,6 +94,8 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { private final LoadableLabel earliestLabel = new LoadableLabel(Bundle.TimelinePanel_earliestLabel_title()); private final LoadableLabel latestLabel = new LoadableLabel(Bundle.TimelinePanel_latestLabel_title()); private final BarChartPanel last30DaysChart = new BarChartPanel(Bundle.TimlinePanel_last30DaysChart_title(), "", ""); + private final OpenTimelineAction openTimelineAction = new OpenTimelineAction(); + private final TimelineDataSourceUtils timelineUtils = TimelineDataSourceUtils.getInstance(); // all loadable components on this tab private final List> loadableComponents = Arrays.asList(earliestLabel, latestLabel, last30DaysChart); @@ -98,6 +119,7 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { ); initComponents(); + setupChartClickListener(); } /** @@ -257,6 +279,27 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { ); }// //GEN-END:initComponents + private void setupChartClickListener() { + this.last30DaysChart.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + this.last30DaysChart.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + + TimelinePanel.this.notifyParentClose(); + openTimelineAction.performAction(); + try { + TimeLineController controller = TimeLineModule.getController(); + DataSource dataSource = getDataSource(); + if (dataSource != null) { + controller.pushFilters(timelineUtils.getDataSourceFilterState(dataSource)); + } + } catch (NoCurrentCaseException | TskCoreException ex) { + logger.log(Level.WARNING, "Unable to open Timeline view", ex); + } + } + }); + } + // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java index ad9d7a2db2..18ca93cf13 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java @@ -336,7 +336,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { * appropriate artifact and closing the data source summary dialog if open. */ private List getPopup(LastAccessedArtifact record) { - return record == null ? null : navigateToArtifactPopup(record.getArtifact()); + return record == null ? null : getNavigateToArtifactPopup(record.getArtifact()); } /** diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/BarChartPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/BarChartPanel.java index 3f3822f7c2..6e1db485f5 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/BarChartPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/BarChartPanel.java @@ -21,9 +21,12 @@ package org.sleuthkit.autopsy.datasourcesummary.uiutils; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Font; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; import java.util.Collections; import java.util.List; import javax.swing.JLabel; +import javax.swing.JPanel; import org.apache.commons.collections4.CollectionUtils; import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartPanel; @@ -252,10 +255,44 @@ public class BarChartPanel extends AbstractLoadableComponent Date: Tue, 17 Nov 2020 11:07:47 -0500 Subject: [PATCH 06/42] get timeline click listener working --- .../datamodel/TimelineDataSourceUtils.java | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineDataSourceUtils.java diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineDataSourceUtils.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineDataSourceUtils.java new file mode 100644 index 0000000000..3e094300bf --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineDataSourceUtils.java @@ -0,0 +1,95 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit 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.datasourcesummary.datamodel; + +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.timeline.TimeLineController; +import org.sleuthkit.autopsy.timeline.TimeLineModule; +import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.FilterState; +import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.RootFilterState; +import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.TimelineFilter; +import org.sleuthkit.datamodel.TimelineFilter.DataSourceFilter; +import org.sleuthkit.datamodel.TimelineFilter.RootFilter; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Utilities for interacting with Timeline in relation to data sources. + */ +public class TimelineDataSourceUtils { + + private static TimelineDataSourceUtils instance = null; + + /** + * @return Singleton instance of this class. + */ + public static TimelineDataSourceUtils getInstance() { + if (instance == null) { + instance = new TimelineDataSourceUtils(); + } + + return instance; + } + + /** + * Main constructor. Should be instantiated through getInstance(). + */ + private TimelineDataSourceUtils() { + } + + /** + * Retrieves a RootFilter based on the default filter state but only the + * specified dataSource is selected. + * + * @param dataSource The data source. + * @return The root filter representing a default filter with only this data + * source selected. + * @throws NoCurrentCaseException + * @throws TskCoreException + */ + public RootFilter getDataSourceFilter(DataSource dataSource) throws NoCurrentCaseException, TskCoreException { + RootFilterState filterState = getDataSourceFilterState(dataSource); + return filterState == null ? null : filterState.getActiveFilter(); + } + + /** + * Retrieves a TimeLineController based on the default filter state but only + * the specified dataSource is selected. + * + * @param dataSource The data source. + * @return The root filter state representing a default filter with only + * this data source selected. + * @throws NoCurrentCaseException + * @throws TskCoreException + */ + public RootFilterState getDataSourceFilterState(DataSource dataSource) throws NoCurrentCaseException, TskCoreException { + TimeLineController controller = TimeLineModule.getController(); + RootFilterState dataSourceState = controller.getEventsModel().getDefaultEventFilterState().copyOf(); + + for (FilterState filterState : dataSourceState.getDataSourcesFilterState().getSubFilterStates()) { + DataSourceFilter dsFilter = filterState.getFilter(); + if (dsFilter != null) { + filterState.setSelected(dsFilter.getDataSourceID() == dataSource.getId()); + } + + } + + return dataSourceState; + } +} From db6eafb6a9e4beedfbb4ad8383613fdc1d1a8dcd Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 17 Nov 2020 11:44:42 -0500 Subject: [PATCH 07/42] right click for more options --- .../datasourcesummary/ui/AnalysisPanel.form | 21 +++++++++ .../datasourcesummary/ui/AnalysisPanel.java | 15 +++++++ .../datasourcesummary/ui/Bundle.properties | 12 +++++ .../ui/Bundle.properties-MERGED | 12 +++++ .../ui/RecentFilesPanel.form | 44 +++++++++++++++++-- .../ui/RecentFilesPanel.java | 42 ++++++++++++++++-- .../datasourcesummary/ui/TimelinePanel.form | 9 +++- .../datasourcesummary/ui/TimelinePanel.java | 19 +++++--- .../ui/UserActivityPanel.form | 35 +++++++++++++++ .../ui/UserActivityPanel.java | 25 +++++++++++ 10 files changed, 218 insertions(+), 16 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.form index 402b709b38..631c10fa38 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.form @@ -128,6 +128,13 @@ + + + + + + + @@ -196,6 +203,13 @@ + + + + + + + @@ -264,6 +278,13 @@ + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java index d0f14f390d..2f4f52be3f 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java @@ -172,14 +172,17 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { javax.swing.JLabel hashsetHitsLabel = new javax.swing.JLabel(); javax.swing.Box.Filler filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(32767, 2)); javax.swing.JPanel hashSetHitsPanel = hashsetHitsTable; + rightClickForMoreOptions1 = new javax.swing.JLabel(); javax.swing.Box.Filler filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20), new java.awt.Dimension(32767, 20)); javax.swing.JLabel keywordHitsLabel = new javax.swing.JLabel(); javax.swing.Box.Filler filler4 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(32767, 2)); javax.swing.JPanel keywordHitsPanel = keywordHitsTable; + rightClickForMoreOptions2 = new javax.swing.JLabel(); javax.swing.Box.Filler filler5 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20), new java.awt.Dimension(32767, 20)); javax.swing.JLabel interestingItemLabel = new javax.swing.JLabel(); javax.swing.Box.Filler filler6 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(32767, 2)); javax.swing.JPanel interestingItemPanel = interestingItemsTable; + rightClickForMoreOptions3 = new javax.swing.JLabel(); javax.swing.Box.Filler filler3 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 32767)); mainContentPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10)); @@ -202,6 +205,9 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { hashSetHitsPanel.setMinimumSize(new java.awt.Dimension(10, 106)); hashSetHitsPanel.setPreferredSize(new java.awt.Dimension(10, 106)); mainContentPanel.add(hashSetHitsPanel); + + org.openide.awt.Mnemonics.setLocalizedText(rightClickForMoreOptions1, org.openide.util.NbBundle.getMessage(AnalysisPanel.class, "AnalysisPanel.rightClickForMoreOptions1.text")); // NOI18N + mainContentPanel.add(rightClickForMoreOptions1); mainContentPanel.add(filler2); org.openide.awt.Mnemonics.setLocalizedText(keywordHitsLabel, org.openide.util.NbBundle.getMessage(AnalysisPanel.class, "AnalysisPanel.keywordHitsLabel.text")); // NOI18N @@ -213,6 +219,9 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { keywordHitsPanel.setMinimumSize(new java.awt.Dimension(10, 106)); keywordHitsPanel.setPreferredSize(new java.awt.Dimension(10, 106)); mainContentPanel.add(keywordHitsPanel); + + org.openide.awt.Mnemonics.setLocalizedText(rightClickForMoreOptions2, org.openide.util.NbBundle.getMessage(AnalysisPanel.class, "AnalysisPanel.rightClickForMoreOptions2.text")); // NOI18N + mainContentPanel.add(rightClickForMoreOptions2); mainContentPanel.add(filler5); org.openide.awt.Mnemonics.setLocalizedText(interestingItemLabel, org.openide.util.NbBundle.getMessage(AnalysisPanel.class, "AnalysisPanel.interestingItemLabel.text")); // NOI18N @@ -224,6 +233,9 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { interestingItemPanel.setMinimumSize(new java.awt.Dimension(10, 106)); interestingItemPanel.setPreferredSize(new java.awt.Dimension(10, 106)); mainContentPanel.add(interestingItemPanel); + + org.openide.awt.Mnemonics.setLocalizedText(rightClickForMoreOptions3, org.openide.util.NbBundle.getMessage(AnalysisPanel.class, "AnalysisPanel.rightClickForMoreOptions3.text")); // NOI18N + mainContentPanel.add(rightClickForMoreOptions3); mainContentPanel.add(filler3); mainScrollPane.setViewportView(mainContentPanel); @@ -242,5 +254,8 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel rightClickForMoreOptions1; + private javax.swing.JLabel rightClickForMoreOptions2; + private javax.swing.JLabel rightClickForMoreOptions3; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties index 5d9e6adf0c..d7e91d6775 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties @@ -43,3 +43,15 @@ PastCasesPanel.notableFileLabel.text=Cases with Common Items That Were Tagged as PastCasesPanel.sameIdLabel.text=Past Cases with the Same Device IDs DataSourceSummaryTabbedPane.noDataSourceLabel.text=No data source has been selected. TimelinePanel.activityRangeLabel.text=Activity Range +RecentFilesPanel.rightClickForMoreOptions1.text=Right click on row for more options +RecentFilesPanel.rightClickForMoreOptions2.text=Right click on row for more options +RecentFilesPanel.rightClickForMoreOptions3.text=Right click on row for more options +AnalysisPanel.rightClickForMoreOptions1.text=Right click on row for more options +AnalysisPanel.rightClickForMoreOptions2.text=Right click on row for more options +AnalysisPanel.rightClickForMoreOptions3.text=Right click on row for more options +UserActivityPanel.rightClickForMoreOptions1.text=Right click on row for more options +UserActivityPanel.rightClickForMoreOptions2.text=Right click on row for more options +UserActivityPanel.rightClickForMoreOptions3.text=Right click on row for more options +UserActivityPanel.rightClickForMoreOptions4.text=Right click on row for more options +UserActivityPanel.rightClickForMoreOptions5.text=Right click on row for more options +TimelinePanel.clickToNavLabel.text=Click to view data source in the timeline diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED index 4902a46385..a08dff4289 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED @@ -103,6 +103,18 @@ PastCasesPanel.notableFileLabel.text=Cases with Common Items That Were Tagged as PastCasesPanel.sameIdLabel.text=Past Cases with the Same Device IDs DataSourceSummaryTabbedPane.noDataSourceLabel.text=No data source has been selected. TimelinePanel.activityRangeLabel.text=Activity Range +RecentFilesPanel.rightClickForMoreOptions1.text=Right click on row for more options +RecentFilesPanel.rightClickForMoreOptions2.text=Right click on row for more options +RecentFilesPanel.rightClickForMoreOptions3.text=Right click on row for more options +AnalysisPanel.rightClickForMoreOptions1.text=Right click on row for more options +AnalysisPanel.rightClickForMoreOptions2.text=Right click on row for more options +AnalysisPanel.rightClickForMoreOptions3.text=Right click on row for more options +UserActivityPanel.rightClickForMoreOptions1.text=Right click on row for more options +UserActivityPanel.rightClickForMoreOptions2.text=Right click on row for more options +UserActivityPanel.rightClickForMoreOptions3.text=Right click on row for more options +UserActivityPanel.rightClickForMoreOptions4.text=Right click on row for more options +UserActivityPanel.rightClickForMoreOptions5.text=Right click on row for more options +TimelinePanel.clickToNavLabel.text=Click to view data source in the timeline UserActivityPanel_goToArtifact=Go to Artifact UserActivityPanel_goToArtifactContent=Go to File UserActivityPanel_noDataExists=No communication data exists diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.form index 150abf2ed0..8a8ae70a58 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.form @@ -94,7 +94,7 @@ - + @@ -106,7 +106,7 @@ - + @@ -140,7 +140,7 @@ - + @@ -156,7 +156,43 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java index fc87d54d2c..ec4dd3fde2 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java @@ -27,6 +27,7 @@ import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentAttachmentDetails; import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentDownloadDetails; import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentFileDetails; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer; import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.DefaultCellModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.MenuItem; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; @@ -141,6 +142,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { pane.setModel(tableModel); pane.setColumnModel(JTablePanel.getTableColumnModel(list)); pane.setKeyFunction((recentFile) -> recentFile.getPath()); + pane.setCellListener(CellModelTableCellRenderer.getMouseListener()); tablePanelList.add(pane); DataFetchWorker.DataFetchComponents> worker @@ -183,6 +185,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { pane.setModel(tableModel); pane.setKeyFunction((download) -> download.getPath()); pane.setColumnModel(JTablePanel.getTableColumnModel(list)); + pane.setCellListener(CellModelTableCellRenderer.getMouseListener()); tablePanelList.add(pane); DataFetchWorker.DataFetchComponents> worker @@ -225,6 +228,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { pane.setModel(tableModel); pane.setKeyFunction((attachment) -> attachment.getPath()); pane.setColumnModel(JTablePanel.getTableColumnModel(list)); + pane.setCellListener(CellModelTableCellRenderer.getMouseListener()); tablePanelList.add(pane); DataFetchWorker.DataFetchComponents> worker @@ -255,6 +259,9 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { javax.swing.JLabel openDocsLabel = new javax.swing.JLabel(); javax.swing.JLabel downloadLabel = new javax.swing.JLabel(); javax.swing.JLabel attachmentLabel = new javax.swing.JLabel(); + rightClickForMoreOptions1 = new javax.swing.JLabel(); + rightClickForMoreOptions2 = new javax.swing.JLabel(); + rightClickForMoreOptions3 = new javax.swing.JLabel(); setLayout(new java.awt.BorderLayout()); @@ -284,7 +291,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { tablePanel.add(openedDocPane, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 4; + gridBagConstraints.gridy = 5; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; gridBagConstraints.weightx = 1.0; @@ -293,7 +300,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { tablePanel.add(downloadsPane, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 6; + gridBagConstraints.gridy = 8; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; gridBagConstraints.weightx = 1.0; @@ -312,7 +319,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { org.openide.awt.Mnemonics.setLocalizedText(downloadLabel, org.openide.util.NbBundle.getMessage(RecentFilesPanel.class, "RecentFilesPanel.downloadLabel.text")); // NOI18N gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 3; + gridBagConstraints.gridy = 4; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.insets = new java.awt.Insets(20, 0, 0, 0); tablePanel.add(downloadLabel, gridBagConstraints); @@ -320,12 +327,36 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { org.openide.awt.Mnemonics.setLocalizedText(attachmentLabel, org.openide.util.NbBundle.getMessage(RecentFilesPanel.class, "RecentFilesPanel.attachmentLabel.text")); // NOI18N gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 5; + gridBagConstraints.gridy = 7; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; gridBagConstraints.insets = new java.awt.Insets(20, 0, 0, 0); tablePanel.add(attachmentLabel, gridBagConstraints); + org.openide.awt.Mnemonics.setLocalizedText(rightClickForMoreOptions1, org.openide.util.NbBundle.getMessage(RecentFilesPanel.class, "RecentFilesPanel.rightClickForMoreOptions1.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 3; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; + tablePanel.add(rightClickForMoreOptions1, gridBagConstraints); + + org.openide.awt.Mnemonics.setLocalizedText(rightClickForMoreOptions2, org.openide.util.NbBundle.getMessage(RecentFilesPanel.class, "RecentFilesPanel.rightClickForMoreOptions2.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 6; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; + tablePanel.add(rightClickForMoreOptions2, gridBagConstraints); + + org.openide.awt.Mnemonics.setLocalizedText(rightClickForMoreOptions3, org.openide.util.NbBundle.getMessage(RecentFilesPanel.class, "RecentFilesPanel.rightClickForMoreOptions3.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 9; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; + tablePanel.add(rightClickForMoreOptions3, gridBagConstraints); + scrollPane.setViewportView(tablePanel); add(scrollPane, java.awt.BorderLayout.CENTER); @@ -336,5 +367,8 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { private javax.swing.JPanel attachmentsPane; private javax.swing.JPanel downloadsPane; private javax.swing.JPanel openedDocPane; + private javax.swing.JLabel rightClickForMoreOptions1; + private javax.swing.JLabel rightClickForMoreOptions2; + private javax.swing.JLabel rightClickForMoreOptions3; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.form index e3493d7a0d..030472d3e9 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.form +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.form @@ -171,7 +171,7 @@ - + @@ -193,6 +193,13 @@ + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java index 2bc9eff126..9c24b3ce94 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java @@ -220,7 +220,8 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { javax.swing.JPanel earliestLabelPanel = earliestLabel; javax.swing.JPanel latestLabelPanel = latestLabel; javax.swing.Box.Filler filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20)); - javax.swing.JPanel sameIdPanel = last30DaysChart; + javax.swing.JPanel last30DaysPanel = last30DaysChart; + clickToNavLabel = new javax.swing.JLabel(); javax.swing.Box.Filler filler5 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 32767)); mainContentPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10)); @@ -255,12 +256,15 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { filler2.setAlignmentX(0.0F); mainContentPanel.add(filler2); - sameIdPanel.setAlignmentX(0.0F); - sameIdPanel.setMaximumSize(new java.awt.Dimension(600, 300)); - sameIdPanel.setMinimumSize(new java.awt.Dimension(600, 300)); - sameIdPanel.setPreferredSize(new java.awt.Dimension(600, 300)); - sameIdPanel.setVerifyInputWhenFocusTarget(false); - mainContentPanel.add(sameIdPanel); + last30DaysPanel.setAlignmentX(0.0F); + last30DaysPanel.setMaximumSize(new java.awt.Dimension(600, 300)); + last30DaysPanel.setMinimumSize(new java.awt.Dimension(600, 300)); + last30DaysPanel.setPreferredSize(new java.awt.Dimension(600, 300)); + last30DaysPanel.setVerifyInputWhenFocusTarget(false); + mainContentPanel.add(last30DaysPanel); + + org.openide.awt.Mnemonics.setLocalizedText(clickToNavLabel, org.openide.util.NbBundle.getMessage(TimelinePanel.class, "TimelinePanel.clickToNavLabel.text")); // NOI18N + mainContentPanel.add(clickToNavLabel); filler5.setAlignmentX(0.0F); mainContentPanel.add(filler5); @@ -302,5 +306,6 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel clickToNavLabel; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.form index 28560a3ec7..a1a04bbe17 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.form @@ -135,6 +135,13 @@ + + + + + + + @@ -204,6 +211,13 @@ + + + + + + + @@ -273,6 +287,13 @@ + + + + + + + @@ -342,6 +363,13 @@ + + + + + + + @@ -411,6 +439,13 @@ + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java index 18ca93cf13..aeb3f7d6e8 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java @@ -382,22 +382,27 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { javax.swing.JLabel programsRunLabel = new javax.swing.JLabel(); javax.swing.Box.Filler filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2)); javax.swing.JPanel topProgramsTablePanel = topProgramsTable; + rightClickForMoreOptions1 = new javax.swing.JLabel(); javax.swing.Box.Filler filler3 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20)); javax.swing.JLabel recentDomainsLabel = new javax.swing.JLabel(); javax.swing.Box.Filler filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2)); javax.swing.JPanel recentDomainsTablePanel = recentDomainsTable; + rightClickForMoreOptions2 = new javax.swing.JLabel(); javax.swing.Box.Filler filler4 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20)); javax.swing.JLabel topWebSearchLabel = new javax.swing.JLabel(); javax.swing.Box.Filler filler5 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2)); javax.swing.JPanel topWebSearches = topWebSearchesTable; + rightClickForMoreOptions3 = new javax.swing.JLabel(); javax.swing.Box.Filler filler6 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20)); javax.swing.JLabel topDevicesAttachedLabel = new javax.swing.JLabel(); javax.swing.Box.Filler filler7 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2)); javax.swing.JPanel recentDevicesAttached = topDevicesAttachedTable; + rightClickForMoreOptions4 = new javax.swing.JLabel(); javax.swing.Box.Filler filler8 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20)); javax.swing.JLabel recentAccountsLabel = new javax.swing.JLabel(); javax.swing.Box.Filler filler9 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2)); javax.swing.JPanel topAccounts = topAccountsTable; + rightClickForMoreOptions5 = new javax.swing.JLabel(); setLayout(new java.awt.BorderLayout()); @@ -426,6 +431,9 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { topProgramsTablePanel.setMinimumSize(new java.awt.Dimension(10, 106)); topProgramsTablePanel.setPreferredSize(new java.awt.Dimension(10, 106)); contentPanel.add(topProgramsTablePanel); + + org.openide.awt.Mnemonics.setLocalizedText(rightClickForMoreOptions1, org.openide.util.NbBundle.getMessage(UserActivityPanel.class, "UserActivityPanel.rightClickForMoreOptions1.text")); // NOI18N + contentPanel.add(rightClickForMoreOptions1); contentPanel.add(filler3); recentDomainsLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); @@ -438,6 +446,9 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { recentDomainsTablePanel.setMinimumSize(new java.awt.Dimension(10, 106)); recentDomainsTablePanel.setPreferredSize(new java.awt.Dimension(10, 106)); contentPanel.add(recentDomainsTablePanel); + + org.openide.awt.Mnemonics.setLocalizedText(rightClickForMoreOptions2, org.openide.util.NbBundle.getMessage(UserActivityPanel.class, "UserActivityPanel.rightClickForMoreOptions2.text")); // NOI18N + contentPanel.add(rightClickForMoreOptions2); contentPanel.add(filler4); topWebSearchLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); @@ -450,6 +461,9 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { topWebSearches.setMinimumSize(new java.awt.Dimension(10, 106)); topWebSearches.setPreferredSize(new java.awt.Dimension(10, 106)); contentPanel.add(topWebSearches); + + org.openide.awt.Mnemonics.setLocalizedText(rightClickForMoreOptions3, org.openide.util.NbBundle.getMessage(UserActivityPanel.class, "UserActivityPanel.rightClickForMoreOptions3.text")); // NOI18N + contentPanel.add(rightClickForMoreOptions3); contentPanel.add(filler6); topDevicesAttachedLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); @@ -462,6 +476,9 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { recentDevicesAttached.setMinimumSize(new java.awt.Dimension(10, 106)); recentDevicesAttached.setPreferredSize(new java.awt.Dimension(10, 106)); contentPanel.add(recentDevicesAttached); + + org.openide.awt.Mnemonics.setLocalizedText(rightClickForMoreOptions4, org.openide.util.NbBundle.getMessage(UserActivityPanel.class, "UserActivityPanel.rightClickForMoreOptions4.text")); // NOI18N + contentPanel.add(rightClickForMoreOptions4); contentPanel.add(filler8); recentAccountsLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); @@ -475,11 +492,19 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { topAccounts.setPreferredSize(new java.awt.Dimension(10, 106)); contentPanel.add(topAccounts); + org.openide.awt.Mnemonics.setLocalizedText(rightClickForMoreOptions5, org.openide.util.NbBundle.getMessage(UserActivityPanel.class, "UserActivityPanel.rightClickForMoreOptions5.text")); // NOI18N + contentPanel.add(rightClickForMoreOptions5); + contentScrollPane.setViewportView(contentPanel); add(contentScrollPane, java.awt.BorderLayout.CENTER); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel rightClickForMoreOptions1; + private javax.swing.JLabel rightClickForMoreOptions2; + private javax.swing.JLabel rightClickForMoreOptions3; + private javax.swing.JLabel rightClickForMoreOptions4; + private javax.swing.JLabel rightClickForMoreOptions5; // End of variables declaration//GEN-END:variables } From bd5299242d3e7354a537849c5dbfbb2a80dc58aa Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 17 Nov 2020 12:06:09 -0500 Subject: [PATCH 08/42] preparing to update analysis tab --- .../sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties | 3 --- 1 file changed, 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties index d7e91d6775..a68f4b2b11 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties @@ -46,9 +46,6 @@ TimelinePanel.activityRangeLabel.text=Activity Range RecentFilesPanel.rightClickForMoreOptions1.text=Right click on row for more options RecentFilesPanel.rightClickForMoreOptions2.text=Right click on row for more options RecentFilesPanel.rightClickForMoreOptions3.text=Right click on row for more options -AnalysisPanel.rightClickForMoreOptions1.text=Right click on row for more options -AnalysisPanel.rightClickForMoreOptions2.text=Right click on row for more options -AnalysisPanel.rightClickForMoreOptions3.text=Right click on row for more options UserActivityPanel.rightClickForMoreOptions1.text=Right click on row for more options UserActivityPanel.rightClickForMoreOptions2.text=Right click on row for more options UserActivityPanel.rightClickForMoreOptions3.text=Right click on row for more options From 53f1cdf7a5df190eddba1f2159fce1e313f4ad9d Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 17 Nov 2020 12:07:42 -0500 Subject: [PATCH 09/42] revert analysis summary --- .../datamodel/AnalysisSummary.java | 81 +++++-------------- .../datasourcesummary/ui/AnalysisPanel.form | 21 ----- .../datasourcesummary/ui/AnalysisPanel.java | 51 +++--------- 3 files changed, 31 insertions(+), 122 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java index 55d0c0b716..9d35e3d28d 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java @@ -94,7 +94,7 @@ public class AnalysisSummary implements DefaultArtifactUpdateGovernor { * @throws SleuthkitCaseProviderException * @throws TskCoreException */ - public List getHashsetCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { + public List> getHashsetCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { return getCountsData(dataSource, TYPE_SET_NAME, ARTIFACT_TYPE.TSK_HASHSET_HIT); } @@ -108,10 +108,10 @@ public class AnalysisSummary implements DefaultArtifactUpdateGovernor { * @throws SleuthkitCaseProviderException * @throws TskCoreException */ - public List getKeywordCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { + public List> getKeywordCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { return getCountsData(dataSource, TYPE_SET_NAME, ARTIFACT_TYPE.TSK_KEYWORD_HIT).stream() // make sure we have a valid set and that that set does not belong to the set of excluded items - .filter((record) -> record != null && record.getIdentifier()!= null && !EXCLUDED_KEYWORD_SEARCH_ITEMS.contains(record.getIdentifier().toUpperCase().trim())) + .filter((pair) -> pair != null && pair.getKey() != null && !EXCLUDED_KEYWORD_SEARCH_ITEMS.contains(pair.getKey().toUpperCase().trim())) .collect(Collectors.toList()); } @@ -119,32 +119,33 @@ public class AnalysisSummary implements DefaultArtifactUpdateGovernor { * Gets counts for interesting item hits. * * @param dataSource The datasource for which to identify interesting item - * hits. + * hits. * * @return The interesting item set name with the number of hits in - * descending order. + * descending order. * * @throws SleuthkitCaseProviderException * @throws TskCoreException */ - public List getInterestingItemCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { + public List> getInterestingItemCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { return getCountsData(dataSource, TYPE_SET_NAME, ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT); } /** * Get counts for the artifact of the specified type. * - * @param dataSource The datasource. - * @param keyType The attribute to use as the key type. + * @param dataSource The datasource. + * @param keyType The attribute to use as the key type. * @param artifactTypes The types of artifacts for which to query. * - * @return A list of AnalysisCountRecord. This list is sorted by the count - * descending max to min. + * @return A list of key value pairs where the key is the attribute type + * value and the value is the count of items found. This list is + * sorted by the count descending max to min. * * @throws SleuthkitCaseProviderException * @throws TskCoreException */ - private List getCountsData(DataSource dataSource, BlackboardAttribute.Type keyType, ARTIFACT_TYPE... artifactTypes) + private List> getCountsData(DataSource dataSource, BlackboardAttribute.Type keyType, ARTIFACT_TYPE... artifactTypes) throws SleuthkitCaseProviderException, TskCoreException { if (dataSource == null) { @@ -160,64 +161,18 @@ public class AnalysisSummary implements DefaultArtifactUpdateGovernor { } // group those based on the value of the attribute type that should serve as a key - Map countedKeys = artifacts.stream() + Map countedKeys = artifacts.stream() .map((art) -> { String key = DataSourceInfoUtilities.getStringOrNull(art, keyType); - return (StringUtils.isBlank(key)) ? null : Pair.of(key, art); + return (StringUtils.isBlank(key)) ? null : key; }) .filter((key) -> key != null) - .collect(Collectors.toMap( - (r) -> r.getLeft(), - (r) -> new AnalysisCountRecord(r.getLeft(), 1, r.getRight()), - (r1, r2) -> new AnalysisCountRecord(r1.getIdentifier(), r1.getCount() + r2.getCount(), r1.getArtifact()))); + .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); // sort from max to min counts - return countedKeys.values().stream() - .sorted((a, b) -> -Long.compare(a.getCount(), b.getCount())) + return countedKeys.entrySet().stream() + .map((e) -> Pair.of(e.getKey(), e.getValue())) + .sorted((a, b) -> -a.getValue().compareTo(b.getValue())) .collect(Collectors.toList()); } - - /** - * A record for an analysis item and its count. - */ - public static class AnalysisCountRecord { - - private final String identifier; - private final long count; - private final BlackboardArtifact artifact; - - /** - * Main constructor. - * - * @param identifier The identifier. - * @param count The count for how many times found. - * @param artifact The artifact. - */ - AnalysisCountRecord(String identifier, long count, BlackboardArtifact artifact) { - this.identifier = identifier; - this.count = count; - this.artifact = artifact; - } - - /** - * @return The identifier for this analysis record. - */ - public String getIdentifier() { - return identifier; - } - - /** - * @return How many times found. - */ - public long getCount() { - return count; - } - - /** - * @return The relevant artifact. - */ - public BlackboardArtifact getArtifact() { - return artifact; - } - } } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.form index 631c10fa38..402b709b38 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.form @@ -128,13 +128,6 @@ - - - - - - - @@ -203,13 +196,6 @@ - - - - - - - @@ -278,13 +264,6 @@ - - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java index 2f4f52be3f..34dfa97a13 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java @@ -21,11 +21,10 @@ package org.sleuthkit.autopsy.datasourcesummary.ui; import java.util.Arrays; import java.util.List; import java.util.function.Function; +import org.apache.commons.lang3.tuple.Pair; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.datasourcesummary.datamodel.AnalysisSummary; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.AnalysisSummary.AnalysisCountRecord; import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.DefaultCellModel; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.MenuItem; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel; @@ -59,30 +58,30 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { /** * Default Column definitions for each table */ - private final List> DEFAULT_COLUMNS = Arrays.asList( + private static final List>> DEFAULT_COLUMNS = Arrays.asList( new ColumnModel<>( Bundle.AnalysisPanel_keyColumn_title(), - (r) -> new DefaultCellModel(r.getIdentifier()).setPopupMenu(getPopup(r)), + (pair) -> new DefaultCellModel(pair.getKey()), 300 ), new ColumnModel<>( Bundle.AnalysisPanel_countColumn_title(), - (r) -> new DefaultCellModel(String.valueOf(Long.toString(r.getCount()))).setPopupMenu(getPopup(r)), + (pair) -> new DefaultCellModel(String.valueOf(pair.getValue())), 100 ) ); - private final Function DEFAULT_KEY_PROVIDER = (pair) -> pair.getIdentifier(); + private static final Function, String> DEFAULT_KEY_PROVIDER = (pair) -> pair.getKey(); - private final JTablePanel hashsetHitsTable + private final JTablePanel> hashsetHitsTable = JTablePanel.getJTablePanel(DEFAULT_COLUMNS) .setKeyFunction(DEFAULT_KEY_PROVIDER); - private final JTablePanel keywordHitsTable + private final JTablePanel> keywordHitsTable = JTablePanel.getJTablePanel(DEFAULT_COLUMNS) .setKeyFunction(DEFAULT_KEY_PROVIDER); - private final JTablePanel interestingItemsTable + private final JTablePanel> interestingItemsTable = JTablePanel.getJTablePanel(DEFAULT_COLUMNS) .setKeyFunction(DEFAULT_KEY_PROVIDER); @@ -91,8 +90,9 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { keywordHitsTable, interestingItemsTable ); - + private final IngestRunningLabel ingestRunningLabel = new IngestRunningLabel(); + /** * All of the components necessary for data fetch swing workers to load data @@ -129,24 +129,14 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { initComponents(); } - /** - * Takes a base class of AnalysisCountRecord and provides the pertinent menu - * items. going to artifact. - * - * @param record The AnalysisCountRecord instance. - * @return The menu items list containing one action or navigating to the - * appropriate artifact and closing the data source summary dialog if open. - */ - private List getPopup(AnalysisCountRecord record) { - return record == null ? null : getNavigateToArtifactPopup(record.getArtifact()); - } - + @Override public void close() { ingestRunningLabel.unregister(); super.close(); } - + + @Override protected void fetchInformation(DataSource dataSource) { fetchInformation(dataFetchComponents, dataSource); @@ -172,17 +162,14 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { javax.swing.JLabel hashsetHitsLabel = new javax.swing.JLabel(); javax.swing.Box.Filler filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(32767, 2)); javax.swing.JPanel hashSetHitsPanel = hashsetHitsTable; - rightClickForMoreOptions1 = new javax.swing.JLabel(); javax.swing.Box.Filler filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20), new java.awt.Dimension(32767, 20)); javax.swing.JLabel keywordHitsLabel = new javax.swing.JLabel(); javax.swing.Box.Filler filler4 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(32767, 2)); javax.swing.JPanel keywordHitsPanel = keywordHitsTable; - rightClickForMoreOptions2 = new javax.swing.JLabel(); javax.swing.Box.Filler filler5 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20), new java.awt.Dimension(32767, 20)); javax.swing.JLabel interestingItemLabel = new javax.swing.JLabel(); javax.swing.Box.Filler filler6 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(32767, 2)); javax.swing.JPanel interestingItemPanel = interestingItemsTable; - rightClickForMoreOptions3 = new javax.swing.JLabel(); javax.swing.Box.Filler filler3 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 32767)); mainContentPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10)); @@ -205,9 +192,6 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { hashSetHitsPanel.setMinimumSize(new java.awt.Dimension(10, 106)); hashSetHitsPanel.setPreferredSize(new java.awt.Dimension(10, 106)); mainContentPanel.add(hashSetHitsPanel); - - org.openide.awt.Mnemonics.setLocalizedText(rightClickForMoreOptions1, org.openide.util.NbBundle.getMessage(AnalysisPanel.class, "AnalysisPanel.rightClickForMoreOptions1.text")); // NOI18N - mainContentPanel.add(rightClickForMoreOptions1); mainContentPanel.add(filler2); org.openide.awt.Mnemonics.setLocalizedText(keywordHitsLabel, org.openide.util.NbBundle.getMessage(AnalysisPanel.class, "AnalysisPanel.keywordHitsLabel.text")); // NOI18N @@ -219,9 +203,6 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { keywordHitsPanel.setMinimumSize(new java.awt.Dimension(10, 106)); keywordHitsPanel.setPreferredSize(new java.awt.Dimension(10, 106)); mainContentPanel.add(keywordHitsPanel); - - org.openide.awt.Mnemonics.setLocalizedText(rightClickForMoreOptions2, org.openide.util.NbBundle.getMessage(AnalysisPanel.class, "AnalysisPanel.rightClickForMoreOptions2.text")); // NOI18N - mainContentPanel.add(rightClickForMoreOptions2); mainContentPanel.add(filler5); org.openide.awt.Mnemonics.setLocalizedText(interestingItemLabel, org.openide.util.NbBundle.getMessage(AnalysisPanel.class, "AnalysisPanel.interestingItemLabel.text")); // NOI18N @@ -233,9 +214,6 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { interestingItemPanel.setMinimumSize(new java.awt.Dimension(10, 106)); interestingItemPanel.setPreferredSize(new java.awt.Dimension(10, 106)); mainContentPanel.add(interestingItemPanel); - - org.openide.awt.Mnemonics.setLocalizedText(rightClickForMoreOptions3, org.openide.util.NbBundle.getMessage(AnalysisPanel.class, "AnalysisPanel.rightClickForMoreOptions3.text")); // NOI18N - mainContentPanel.add(rightClickForMoreOptions3); mainContentPanel.add(filler3); mainScrollPane.setViewportView(mainContentPanel); @@ -254,8 +232,5 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JLabel rightClickForMoreOptions1; - private javax.swing.JLabel rightClickForMoreOptions2; - private javax.swing.JLabel rightClickForMoreOptions3; // End of variables declaration//GEN-END:variables } From 4367c6dc036594f086952a77bad71dc82b890524 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 17 Nov 2020 14:08:37 -0500 Subject: [PATCH 10/42] updates --- .../ui/BaseDataSourceSummaryPanel.java | 4 +-- .../ui/Bundle.properties-MERGED | 5 +-- .../ui/RecentFilesPanel.java | 2 +- .../ui/UserActivityPanel.java | 33 ++++++++++--------- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java index d4ff6ef081..c3637df41a 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java @@ -56,7 +56,7 @@ import org.sleuthkit.datamodel.TskCoreException; * Base class from which other tabs in data source summary derive. */ @Messages({"UserActivityPanel_goToArtifact=Go to Artifact", - "UserActivityPanel_goToArtifactContent=Go to File"}) + "UserActivityPanel_goToArtifactContent=Go to Artifact"}) abstract class BaseDataSourceSummaryPanel extends JPanel { private static final long serialVersionUID = 1L; @@ -263,7 +263,7 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { * @param artifact The artifact. * @return The menu item list for a go to artifact menu item. */ - protected List getNavigateToArtifactContentPopup(BlackboardArtifact artifact) { + protected List geNavigateToArtifactContentPopup(BlackboardArtifact artifact) { return artifact == null ? null : Arrays.asList( new CellModelTableCellRenderer.DefaultMenuItem( Bundle.UserActivityPanel_goToArtifactContent(), diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED index a08dff4289..09b3c69e31 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED @@ -106,9 +106,6 @@ TimelinePanel.activityRangeLabel.text=Activity Range RecentFilesPanel.rightClickForMoreOptions1.text=Right click on row for more options RecentFilesPanel.rightClickForMoreOptions2.text=Right click on row for more options RecentFilesPanel.rightClickForMoreOptions3.text=Right click on row for more options -AnalysisPanel.rightClickForMoreOptions1.text=Right click on row for more options -AnalysisPanel.rightClickForMoreOptions2.text=Right click on row for more options -AnalysisPanel.rightClickForMoreOptions3.text=Right click on row for more options UserActivityPanel.rightClickForMoreOptions1.text=Right click on row for more options UserActivityPanel.rightClickForMoreOptions2.text=Right click on row for more options UserActivityPanel.rightClickForMoreOptions3.text=Right click on row for more options @@ -116,7 +113,7 @@ UserActivityPanel.rightClickForMoreOptions4.text=Right click on row for more opt UserActivityPanel.rightClickForMoreOptions5.text=Right click on row for more options TimelinePanel.clickToNavLabel.text=Click to view data source in the timeline UserActivityPanel_goToArtifact=Go to Artifact -UserActivityPanel_goToArtifactContent=Go to File +UserActivityPanel_goToArtifactContent=Go to Artifact UserActivityPanel_noDataExists=No communication data exists UserActivityPanel_tab_title=User Activity UserActivityPanel_TopAccountTableModel_accountType_header=Account Type diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java index ec4dd3fde2..021b1c4fa1 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java @@ -88,7 +88,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { * appropriate artifact and closing the data source summary dialog if open. */ private List getPopup(RecentFileDetails record) { - return record == null ? null : getNavigateToArtifactContentPopup(record.getArtifact()); + return record == null ? null : geNavigateToArtifactContentPopup(record.getArtifact()); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java index aeb3f7d6e8..32fce07859 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java @@ -95,7 +95,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { (prog) -> { return new DefaultCellModel(prog.getProgramName()) .setTooltip(prog.getProgramPath()) - .setPopupMenu(getPopup(prog)); + .setPopupMenu(getNavigateToArtifactPopup(prog.getArtifact())); }, 250), // program folder column @@ -107,7 +107,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { prog.getProgramPath(), prog.getProgramName())) .setTooltip(prog.getProgramPath()) - .setPopupMenu(getPopup(prog)); + .setPopupMenu(getNavigateToArtifactPopup(prog.getArtifact())); }, 150), // run count column @@ -116,7 +116,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { (prog) -> { String runTimes = prog.getRunTimes() == null ? "" : Long.toString(prog.getRunTimes()); return new DefaultCellModel(runTimes) - .setPopupMenu(getPopup(prog)); + .setPopupMenu(getNavigateToArtifactPopup(prog.getArtifact())); }, 80), // last run date column @@ -124,7 +124,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { Bundle.UserActivityPanel_TopProgramsTableModel_lastrun_header(), (prog) -> { return new DefaultCellModel(getFormatted(prog.getLastAccessed())) - .setPopupMenu(getPopup(prog)); + .setPopupMenu(getNavigateToArtifactPopup(prog.getArtifact())); }, 150) )) @@ -137,7 +137,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { Bundle.UserActivityPanel_TopDomainsTableModel_domain_header(), (recentDomain) -> { return new DefaultCellModel(recentDomain.getDomain()) - .setPopupMenu(getPopup(recentDomain)); + .setPopupMenu(getNavigateToArtifactPopup(recentDomain.getArtifact())); }, 250), // count column @@ -146,13 +146,16 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { (recentDomain) -> { String visitTimes = recentDomain.getVisitTimes() == null ? "" : Long.toString(recentDomain.getVisitTimes()); return new DefaultCellModel(visitTimes) - .setPopupMenu(getPopup(recentDomain)); + .setPopupMenu(getNavigateToArtifactPopup(recentDomain.getArtifact())); }, 100), // last accessed column new ColumnModel<>( Bundle.UserActivityPanel_TopDomainsTableModel_lastAccess_header(), - (recentDomain) -> new DefaultCellModel(getFormatted(recentDomain.getLastAccessed())), + (recentDomain) -> { + return new DefaultCellModel(getFormatted(recentDomain.getLastAccessed())) + .setPopupMenu(getNavigateToArtifactPopup(recentDomain.getArtifact())); + }, 150) )) .setKeyFunction((domain) -> domain.getDomain()); @@ -164,7 +167,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { Bundle.UserActivityPanel_TopWebSearchTableModel_searchString_header(), (webSearch) -> { return new DefaultCellModel(webSearch.getSearchString()) - .setPopupMenu(getPopup(webSearch)); + .setPopupMenu(getNavigateToArtifactPopup(webSearch.getArtifact())); }, 250 ), @@ -173,7 +176,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { Bundle.UserActivityPanel_TopWebSearchTableModel_dateAccessed_header(), (webSearch) -> { return new DefaultCellModel(getFormatted(webSearch.getLastAccessed())) - .setPopupMenu(getPopup(webSearch)); + .setPopupMenu(getNavigateToArtifactPopup(webSearch.getArtifact())); }, 150 ), @@ -182,7 +185,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { Bundle.UserActivityPanel_TopWebSearchTableModel_translatedResult_header(), (webSearch) -> { return new DefaultCellModel(webSearch.getTranslatedResult()) - .setPopupMenu(getPopup(webSearch)); + .setPopupMenu(getNavigateToArtifactPopup(webSearch.getArtifact())); }, 250 ) @@ -196,7 +199,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { Bundle.UserActivityPanel_TopDeviceAttachedTableModel_deviceId_header(), (device) -> { return new DefaultCellModel(device.getDeviceId()) - .setPopupMenu(getPopup(device)); + .setPopupMenu(getNavigateToArtifactPopup(device.getArtifact())); }, 250 ), @@ -205,7 +208,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { Bundle.UserActivityPanel_TopDeviceAttachedTableModel_dateAccessed_header(), (device) -> { return new DefaultCellModel(getFormatted(device.getLastAccessed())) - .setPopupMenu(getPopup(device)); + .setPopupMenu(getNavigateToArtifactPopup(device.getArtifact())); }, 150 ), @@ -219,7 +222,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { ? make + model : String.format("%s - %s", make, model); return new DefaultCellModel(makeModelString) - .setPopupMenu(getPopup(device)); + .setPopupMenu(getNavigateToArtifactPopup(device.getArtifact())); }, 250 ) @@ -233,7 +236,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { Bundle.UserActivityPanel_TopAccountTableModel_accountType_header(), (account) -> { return new DefaultCellModel(account.getAccountType()) - .setPopupMenu(getPopup(account)); + .setPopupMenu(getNavigateToArtifactPopup(account.getArtifact())); }, 250 ), @@ -242,7 +245,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { Bundle.UserActivityPanel_TopAccountTableModel_lastAccess_header(), (account) -> { return new DefaultCellModel(getFormatted(account.getLastAccessed())) - .setPopupMenu(getPopup(account)); + .setPopupMenu(getNavigateToArtifactPopup(account.getArtifact())); }, 150 ) From 17848554858ca592f7d1ee1a2bd8c7cee332682e Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 19 Nov 2020 15:47:17 -0500 Subject: [PATCH 11/42] file navigation working --- .../ui/BaseDataSourceSummaryPanel.java | 111 ++++++++++++++---- .../ui/Bundle.properties-MERGED | 2 +- .../ui/RecentFilesPanel.java | 43 +++++-- .../ui/UserActivityPanel.java | 33 +++--- .../uiutils/CellModelTableCellRenderer.java | 23 +++- 5 files changed, 155 insertions(+), 57 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java index c3637df41a..155471c18c 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java @@ -19,17 +19,25 @@ package org.sleuthkit.autopsy.datasourcesummary.ui; import java.beans.PropertyChangeEvent; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Set; import java.util.function.Predicate; import java.util.logging.Level; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; import javax.swing.JPanel; import javax.swing.SwingWorker; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang3.StringUtils; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datasourcesummary.datamodel.IngestModuleCheckUtil; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; @@ -43,6 +51,7 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableComponent; import org.sleuthkit.autopsy.datasourcesummary.uiutils.SwingWorkerSequentialExecutor; import org.sleuthkit.autopsy.datasourcesummary.uiutils.UpdateGovernor; import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; +import org.sleuthkit.autopsy.directorytree.ViewContextAction; import org.sleuthkit.autopsy.ingest.IngestManager.IngestJobEvent; import org.sleuthkit.autopsy.ingest.ModuleContentEvent; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; @@ -56,7 +65,7 @@ import org.sleuthkit.datamodel.TskCoreException; * Base class from which other tabs in data source summary derive. */ @Messages({"UserActivityPanel_goToArtifact=Go to Artifact", - "UserActivityPanel_goToArtifactContent=Go to Artifact"}) + "UserActivityPanel_goToFile=Go to File"}) abstract class BaseDataSourceSummaryPanel extends JPanel { private static final long serialVersionUID = 1L; @@ -238,22 +247,73 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { * closes data source summary dialog if open. * * @param artifact The artifact. - * @return The menu item list for a go to artifact menu item. + * @return The menu item for a go to artifact menu item. */ - protected List getNavigateToArtifactPopup(BlackboardArtifact artifact) { - return artifact == null ? null : Arrays.asList( - new CellModelTableCellRenderer.DefaultMenuItem( - Bundle.UserActivityPanel_goToArtifact(), - () -> { - final DirectoryTreeTopComponent dtc = DirectoryTreeTopComponent.findInstance(); + protected CellModelTableCellRenderer.MenuItem getArtifactNavigateItem(BlackboardArtifact artifact) { + if (artifact == null) { + return null; + } - // Navigate to the source context artifact. - if (dtc != null && artifact != null) { - dtc.viewArtifact(artifact); - } + return new CellModelTableCellRenderer.DefaultMenuItem( + Bundle.UserActivityPanel_goToArtifact(), + () -> { + final DirectoryTreeTopComponent dtc = DirectoryTreeTopComponent.findInstance(); - notifyParentClose(); - })); + // Navigate to the source context artifact. + if (dtc != null && artifact != null) { + dtc.viewArtifact(artifact); + } + + notifyParentClose(); + }); + } + + private static final Pattern windowsDrivePattern = Pattern.compile("^[A-Za-z]\\:(.*)$"); + + /** + * Normalizes the path for lookup in the sleuthkit database (unix endings; remove C:\). + * @param path The path to normalize. + * @return The normalized path. + */ + private String normalizePath(String path) { + if (path == null) { + return null; + } + + String trimmed = path.trim(); + Matcher match = windowsDrivePattern.matcher(trimmed); + if (match.find()) { + return FilenameUtils.normalize(match.group(1), true); + } else { + return FilenameUtils.normalize(trimmed, true); + } + } + + /** + * Creates a menu item to navigate to a file. + * + * @param path The path to the file. + * @return The menu item or null if file cannot be found in data source. + */ + protected CellModelTableCellRenderer.MenuItem getFileNavigateItem(String path) { + if (StringUtils.isNotBlank(path)) { + Path p = Paths.get(path); + String fileName = normalizePath(p.getFileName().toString()); + String directory = normalizePath(p.getParent().toString()); + + if (fileName != null && directory != null) { + try { + List files = Case.getCurrentCaseThrows().getSleuthkitCase().findFiles(getDataSource(), fileName, directory); + if (CollectionUtils.isNotEmpty(files)) { + return getFileNavigateItem(files.get(0)); + } + } catch (TskCoreException | NoCurrentCaseException ex) { + logger.log(Level.WARNING, "There was an error fetching file for path: " + path, ex); + } + } + } + + return null; } /** @@ -263,20 +323,19 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { * @param artifact The artifact. * @return The menu item list for a go to artifact menu item. */ - protected List geNavigateToArtifactContentPopup(BlackboardArtifact artifact) { - return artifact == null ? null : Arrays.asList( - new CellModelTableCellRenderer.DefaultMenuItem( - Bundle.UserActivityPanel_goToArtifactContent(), - () -> { - final DirectoryTreeTopComponent dtc = DirectoryTreeTopComponent.findInstance(); + protected CellModelTableCellRenderer.MenuItem getFileNavigateItem(AbstractFile file) { + if (file == null) { + return null; + } - // Navigate to the source context artifact. - if (dtc != null && artifact != null) { - dtc.viewArtifactContent(artifact); - } + return new CellModelTableCellRenderer.DefaultMenuItem( + Bundle.UserActivityPanel_goToFile(), + () -> { + new ViewContextAction(Bundle.UserActivityPanel_goToFile(), file) + .actionPerformed(null); - notifyParentClose(); - })); + notifyParentClose(); + }); } /** diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED index 09b3c69e31..fc3ebb09cd 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED @@ -113,7 +113,7 @@ UserActivityPanel.rightClickForMoreOptions4.text=Right click on row for more opt UserActivityPanel.rightClickForMoreOptions5.text=Right click on row for more options TimelinePanel.clickToNavLabel.text=Click to view data source in the timeline UserActivityPanel_goToArtifact=Go to Artifact -UserActivityPanel_goToArtifactContent=Go to Artifact +UserActivityPanel_goToFile=Go to File UserActivityPanel_noDataExists=No communication data exists UserActivityPanel_tab_title=User Activity UserActivityPanel_TopAccountTableModel_accountType_header=Account Type diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java index 021b1c4fa1..db708af9ec 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.datasourcesummary.ui; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.function.Supplier; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.datasourcesummary.datamodel.IngestModuleCheckUtil; import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary; @@ -81,14 +82,32 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { /** * Takes a base class of RecentFileDetails and provides the pertinent menu - * items. going to artifact. + * items. * * @param record The RecentFileDetails instance. * @return The menu items list containing one action or navigating to the - * appropriate artifact and closing the data source summary dialog if open. + * appropriate artifact/file and closing the data source summary dialog if + * open. */ - private List getPopup(RecentFileDetails record) { - return record == null ? null : geNavigateToArtifactContentPopup(record.getArtifact()); + private Supplier> getPopupFunct(RecentFileDetails record) { + return () -> { + if (record == null) { + return null; + } + + List toRet = new ArrayList<>(); + + MenuItem fileNav = getFileNavigateItem(record.getPath()); + if (fileNav != null) { + toRet.add(fileNav); + } + + if (record.getArtifact() != null) { + toRet.add(getArtifactNavigateItem(record.getArtifact())); + } + + return (toRet.size() > 0) ? toRet : null; + }; } @Override @@ -128,12 +147,12 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { new ColumnModel<>(Bundle.RecentFilePanel_col_header_path(), (prog) -> { return new DefaultCellModel(prog.getPath()) - .setPopupMenu(getPopup(prog)); + .setPopupMenuRetriever(getPopupFunct(prog)); }, 250), new ColumnModel<>(Bundle.RecentFilesPanel_col_head_date(), (prog) -> { return new DefaultCellModel(prog.getDateAsString()) - .setPopupMenu(getPopup(prog)); + .setPopupMenuRetriever(getPopupFunct(prog)); }, 80)); ListTableModel tableModel = JTablePanel.getTableModel(list); @@ -166,17 +185,17 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { new ColumnModel<>(Bundle.RecentFilePanel_col_header_domain(), (prog) -> { return new DefaultCellModel(prog.getWebDomain()) - .setPopupMenu(getPopup(prog)); + .setPopupMenuRetriever(getPopupFunct(prog)); }, 100), new ColumnModel<>(Bundle.RecentFilePanel_col_header_path(), (prog) -> { return new DefaultCellModel(prog.getPath()) - .setPopupMenu(getPopup(prog)); + .setPopupMenuRetriever(getPopupFunct(prog)); }, 250), new ColumnModel<>(Bundle.RecentFilesPanel_col_head_date(), (prog) -> { return new DefaultCellModel(prog.getDateAsString()) - .setPopupMenu(getPopup(prog)); + .setPopupMenuRetriever(getPopupFunct(prog)); }, 80)); ListTableModel tableModel = JTablePanel.getTableModel(list); @@ -209,17 +228,17 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { new ColumnModel<>(Bundle.RecentFilePanel_col_header_path(), (prog) -> { return new DefaultCellModel(prog.getPath()) - .setPopupMenu(getPopup(prog)); + .setPopupMenuRetriever(getPopupFunct(prog)); }, 250), new ColumnModel<>(Bundle.RecentFilesPanel_col_head_date(), (prog) -> { return new DefaultCellModel(prog.getDateAsString()) - .setPopupMenu(getPopup(prog)); + .setPopupMenuRetriever(getPopupFunct(prog)); }, 80), new ColumnModel<>(Bundle.RecentFilePanel_col_header_sender(), (prog) -> { return new DefaultCellModel(prog.getSender()) - .setPopupMenu(getPopup(prog)); + .setPopupMenuRetriever(getPopupFunct(prog)); }, 150)); ListTableModel tableModel = JTablePanel.getTableModel(list); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java index 32fce07859..afac5607e9 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java @@ -41,6 +41,7 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetch import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel.ColumnModel; +import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.DataSource; /** @@ -95,7 +96,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { (prog) -> { return new DefaultCellModel(prog.getProgramName()) .setTooltip(prog.getProgramPath()) - .setPopupMenu(getNavigateToArtifactPopup(prog.getArtifact())); + .setPopupMenu(getPopup(prog)); }, 250), // program folder column @@ -107,7 +108,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { prog.getProgramPath(), prog.getProgramName())) .setTooltip(prog.getProgramPath()) - .setPopupMenu(getNavigateToArtifactPopup(prog.getArtifact())); + .setPopupMenu(getPopup(prog)); }, 150), // run count column @@ -116,7 +117,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { (prog) -> { String runTimes = prog.getRunTimes() == null ? "" : Long.toString(prog.getRunTimes()); return new DefaultCellModel(runTimes) - .setPopupMenu(getNavigateToArtifactPopup(prog.getArtifact())); + .setPopupMenu(getPopup(prog)); }, 80), // last run date column @@ -124,7 +125,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { Bundle.UserActivityPanel_TopProgramsTableModel_lastrun_header(), (prog) -> { return new DefaultCellModel(getFormatted(prog.getLastAccessed())) - .setPopupMenu(getNavigateToArtifactPopup(prog.getArtifact())); + .setPopupMenu(getPopup(prog)); }, 150) )) @@ -137,7 +138,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { Bundle.UserActivityPanel_TopDomainsTableModel_domain_header(), (recentDomain) -> { return new DefaultCellModel(recentDomain.getDomain()) - .setPopupMenu(getNavigateToArtifactPopup(recentDomain.getArtifact())); + .setPopupMenu(getPopup(recentDomain)); }, 250), // count column @@ -146,7 +147,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { (recentDomain) -> { String visitTimes = recentDomain.getVisitTimes() == null ? "" : Long.toString(recentDomain.getVisitTimes()); return new DefaultCellModel(visitTimes) - .setPopupMenu(getNavigateToArtifactPopup(recentDomain.getArtifact())); + .setPopupMenu(getPopup(recentDomain)); }, 100), // last accessed column @@ -154,7 +155,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { Bundle.UserActivityPanel_TopDomainsTableModel_lastAccess_header(), (recentDomain) -> { return new DefaultCellModel(getFormatted(recentDomain.getLastAccessed())) - .setPopupMenu(getNavigateToArtifactPopup(recentDomain.getArtifact())); + .setPopupMenu(getPopup(recentDomain)); }, 150) )) @@ -167,7 +168,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { Bundle.UserActivityPanel_TopWebSearchTableModel_searchString_header(), (webSearch) -> { return new DefaultCellModel(webSearch.getSearchString()) - .setPopupMenu(getNavigateToArtifactPopup(webSearch.getArtifact())); + .setPopupMenu(getPopup(webSearch)); }, 250 ), @@ -176,7 +177,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { Bundle.UserActivityPanel_TopWebSearchTableModel_dateAccessed_header(), (webSearch) -> { return new DefaultCellModel(getFormatted(webSearch.getLastAccessed())) - .setPopupMenu(getNavigateToArtifactPopup(webSearch.getArtifact())); + .setPopupMenu(getPopup(webSearch)); }, 150 ), @@ -185,7 +186,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { Bundle.UserActivityPanel_TopWebSearchTableModel_translatedResult_header(), (webSearch) -> { return new DefaultCellModel(webSearch.getTranslatedResult()) - .setPopupMenu(getNavigateToArtifactPopup(webSearch.getArtifact())); + .setPopupMenu(getPopup(webSearch)); }, 250 ) @@ -199,7 +200,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { Bundle.UserActivityPanel_TopDeviceAttachedTableModel_deviceId_header(), (device) -> { return new DefaultCellModel(device.getDeviceId()) - .setPopupMenu(getNavigateToArtifactPopup(device.getArtifact())); + .setPopupMenu(getPopup(device)); }, 250 ), @@ -208,7 +209,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { Bundle.UserActivityPanel_TopDeviceAttachedTableModel_dateAccessed_header(), (device) -> { return new DefaultCellModel(getFormatted(device.getLastAccessed())) - .setPopupMenu(getNavigateToArtifactPopup(device.getArtifact())); + .setPopupMenu(getPopup(device)); }, 150 ), @@ -222,7 +223,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { ? make + model : String.format("%s - %s", make, model); return new DefaultCellModel(makeModelString) - .setPopupMenu(getNavigateToArtifactPopup(device.getArtifact())); + .setPopupMenu(getPopup(device)); }, 250 ) @@ -236,7 +237,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { Bundle.UserActivityPanel_TopAccountTableModel_accountType_header(), (account) -> { return new DefaultCellModel(account.getAccountType()) - .setPopupMenu(getNavigateToArtifactPopup(account.getArtifact())); + .setPopupMenu(getPopup(account)); }, 250 ), @@ -245,7 +246,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { Bundle.UserActivityPanel_TopAccountTableModel_lastAccess_header(), (account) -> { return new DefaultCellModel(getFormatted(account.getLastAccessed())) - .setPopupMenu(getNavigateToArtifactPopup(account.getArtifact())); + .setPopupMenu(getPopup(account)); }, 150 ) @@ -339,7 +340,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { * appropriate artifact and closing the data source summary dialog if open. */ private List getPopup(LastAccessedArtifact record) { - return record == null ? null : getNavigateToArtifactPopup(record.getArtifact()); + return record == null ? null : Arrays.asList(getArtifactNavigateItem(record.getArtifact())); } /** diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/CellModelTableCellRenderer.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/CellModelTableCellRenderer.java index 3511101da4..ed3f598a4e 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/CellModelTableCellRenderer.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/CellModelTableCellRenderer.java @@ -20,11 +20,11 @@ package org.sleuthkit.autopsy.datasourcesummary.uiutils; import java.awt.Component; import java.awt.Insets; -import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.function.Supplier; import javax.swing.BorderFactory; import javax.swing.JLabel; import javax.swing.JMenuItem; @@ -161,6 +161,7 @@ public class CellModelTableCellRenderer extends DefaultTableCellRenderer { private HorizontalAlign horizontalAlignment; private Insets insets; private List popupMenu; + private Supplier> menuItemSupplier; /** * Main constructor. @@ -230,7 +231,25 @@ public class CellModelTableCellRenderer extends DefaultTableCellRenderer { @Override public List getPopupMenu() { - return popupMenu == null ? null : Collections.unmodifiableList(popupMenu); + if (popupMenu != null) { + return Collections.unmodifiableList(popupMenu); + } + + if (menuItemSupplier != null) { + return this.menuItemSupplier.get(); + } + + return null; + } + + /** + * Sets a function to lazy load the popup menu items. + * @param menuItemSupplier The lazy load function for popup items. + * @return + */ + public DefaultCellModel setPopupMenuRetriever(Supplier> menuItemSupplier) { + this.menuItemSupplier = menuItemSupplier; + return this; } /** From bf32de479e40b5d5a9e3cd336ba765e37d216f81 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 20 Nov 2020 08:36:21 -0500 Subject: [PATCH 12/42] update for timeline button --- .../datamodel/TimelineSummary.java | 27 +++-- .../datasourcesummary/ui/Bundle.properties | 2 +- .../datasourcesummary/ui/TimelinePanel.form | 8 +- .../datasourcesummary/ui/TimelinePanel.java | 109 ++++++++++++------ 4 files changed, 95 insertions(+), 51 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummary.java index c892c7eec8..46d4a0f827 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummary.java @@ -38,19 +38,12 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TimelineEvent; import org.sleuthkit.datamodel.TimelineEventType; -import org.sleuthkit.datamodel.TimelineFilter; -import org.sleuthkit.datamodel.TimelineFilter.DataSourcesFilter; import org.sleuthkit.datamodel.TimelineFilter.RootFilter; import org.sleuthkit.datamodel.TimelineManager; import org.sleuthkit.datamodel.TskCoreException; import java.util.function.Supplier; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.core.UserPreferences; -import org.sleuthkit.autopsy.timeline.TimeLineController; -import org.sleuthkit.autopsy.timeline.TimeLineModule; -import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.FilterState; -import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.RootFilterState; -import org.sleuthkit.autopsy.timeline.utils.FilterUtils; /** * Provides data source summary information pertaining to Timeline data. @@ -89,9 +82,9 @@ public class TimelineSummary implements DefaultUpdateGovernor { /** * Construct object with given SleuthkitCaseProvider * - * @param caseProvider SleuthkitCaseProvider provider, cannot be null. - * @param timeZoneProvider The timezone provider, cannot be null. - * @param defaulteStateSupplier Provides the default root filter + * @param caseProvider SleuthkitCaseProvider provider; cannot be null. + * @param timeZoneProvider The timezone provider; cannot be null. + * @param defaulteStateSupplier Provides the default root filter function filtered to the data source; cannot be null. */ public TimelineSummary(SleuthkitCaseProvider caseProvider, Supplier timeZoneProvider, DataSourceFilterFunction filterFunction) { this.caseProvider = caseProvider; @@ -161,7 +154,7 @@ public class TimelineSummary implements DefaultUpdateGovernor { // get most recent days activity List mostRecentActivityAmt = getMostRecentActivityAmounts(dateCounts, minRecentDay, maxDay); - return new TimelineSummaryData(minDate, maxDate, mostRecentActivityAmt); + return new TimelineSummaryData(minDate, maxDate, mostRecentActivityAmt, dataSource); } /** @@ -240,6 +233,7 @@ public class TimelineSummary implements DefaultUpdateGovernor { private final Date minDate; private final Date maxDate; private final List histogramActivity; + private final DataSource dataSource; /** * Main constructor. @@ -247,12 +241,14 @@ public class TimelineSummary implements DefaultUpdateGovernor { * @param minDate Earliest usage date recorded for the data source. * @param maxDate Latest usage date recorded for the data source. * @param recentDaysActivity A list of activity prior to and including + * @param dataSource The data source for which this data applies. * the latest usage date by day. */ - TimelineSummaryData(Date minDate, Date maxDate, List recentDaysActivity) { + TimelineSummaryData(Date minDate, Date maxDate, List recentDaysActivity, DataSource dataSource) { this.minDate = minDate; this.maxDate = maxDate; this.histogramActivity = (recentDaysActivity == null) ? Collections.emptyList() : Collections.unmodifiableList(recentDaysActivity); + this.dataSource = dataSource; } /** @@ -276,6 +272,13 @@ public class TimelineSummary implements DefaultUpdateGovernor { public List getMostRecentDaysActivity() { return histogramActivity; } + + /** + * @return The data source that this data applies to. + */ + public DataSource getDataSource() { + return dataSource; + } } /** diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties index a68f4b2b11..f71abb831e 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties @@ -51,4 +51,4 @@ UserActivityPanel.rightClickForMoreOptions2.text=Right click on row for more opt UserActivityPanel.rightClickForMoreOptions3.text=Right click on row for more options UserActivityPanel.rightClickForMoreOptions4.text=Right click on row for more options UserActivityPanel.rightClickForMoreOptions5.text=Right click on row for more options -TimelinePanel.clickToNavLabel.text=Click to view data source in the timeline +TimelinePanel.viewInTimelineBtn.text=View in Timeline diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.form index 030472d3e9..7fc0a1151c 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.form +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.form @@ -193,12 +193,16 @@ - + - + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java index 9c24b3ce94..12da8f60cf 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java @@ -19,19 +19,17 @@ package org.sleuthkit.autopsy.datasourcesummary.ui; import java.awt.Color; -import java.awt.Cursor; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.logging.Level; import org.apache.commons.collections.CollectionUtils; +import org.joda.time.DateTime; +import org.joda.time.Interval; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; @@ -52,13 +50,7 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableLabel; import org.sleuthkit.autopsy.timeline.OpenTimelineAction; import org.sleuthkit.autopsy.timeline.TimeLineController; import org.sleuthkit.autopsy.timeline.TimeLineModule; -import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.FilterState; -import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.RootFilterState; -import org.sleuthkit.autopsy.timeline.utils.FilterUtils; import org.sleuthkit.datamodel.DataSource; -import org.sleuthkit.datamodel.TimelineEventType; -import org.sleuthkit.datamodel.TimelineFilter; -import org.sleuthkit.datamodel.TimelineFilter.DataSourceFilter; import org.sleuthkit.datamodel.TskCoreException; /** @@ -119,7 +111,6 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { ); initComponents(); - setupChartClickListener(); } /** @@ -172,6 +163,9 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { new BarChartSeries(Bundle.TimlinePanel_last30DaysChart_fileEvts_title(), FILE_EVT_COLOR, fileEvtCounts), new BarChartSeries(Bundle.TimlinePanel_last30DaysChart_artifactEvts_title(), ARTIFACT_EVT_COLOR, artifactEvtCounts)); } + + private final Object timelineBtnLock = new Object(); + private TimelineSummaryData curTimelineData = null; /** * Handles displaying the result for each displayable item in the @@ -185,6 +179,61 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { earliestLabel.showDataFetchResult(DataFetchResult.getSubResult(result, r -> formatDate(r.getMinDate(), EARLIEST_LATEST_FORMAT))); latestLabel.showDataFetchResult(DataFetchResult.getSubResult(result, r -> formatDate(r.getMaxDate(), EARLIEST_LATEST_FORMAT))); last30DaysChart.showDataFetchResult(DataFetchResult.getSubResult(result, r -> parseChartData(r.getMostRecentDaysActivity()))); + + if (result != null + && result.getResultType() == DataFetchResult.ResultType.SUCCESS + && result.getData() != null) { + + synchronized (this.timelineBtnLock) { + this.curTimelineData = result.getData(); + this.viewInTimelineBtn.setEnabled(true); + } + } else { + synchronized (this.timelineBtnLock) { + this.viewInTimelineBtn.setEnabled(false); + } + } + } + + /** + * Action that occurs when 'View in Timeline' button is pressed. + */ + private void openFilteredChart() { + DataSource dataSource = null; + Date minDate = null; + Date maxDate = null; + + + // get date from current timelineData if that data exists. + synchronized (this.timelineBtnLock) { + if (curTimelineData == null) { + return; + } + + dataSource = curTimelineData.getDataSource(); + minDate = curTimelineData.getMinDate(); + maxDate = curTimelineData.getMaxDate(); + } + + // notify dialog (if in dialog) should close. + TimelinePanel.this.notifyParentClose(); + + // open the timeline filtered to data source and zoomed in on interval + openTimelineAction.performAction(); + try { + TimeLineController controller = TimeLineModule.getController(); + if (dataSource != null) { + controller.pushFilters(timelineUtils.getDataSourceFilterState(dataSource)); + } + + if (minDate != null && maxDate != null) { + Interval timeSpan = new Interval(new DateTime(minDate), new DateTime(maxDate)); + controller.pushTimeRange(timeSpan); + } + + } catch (NoCurrentCaseException | TskCoreException ex) { + logger.log(Level.WARNING, "Unable to open Timeline view", ex); + } } @Override @@ -221,7 +270,7 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { javax.swing.JPanel latestLabelPanel = latestLabel; javax.swing.Box.Filler filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20)); javax.swing.JPanel last30DaysPanel = last30DaysChart; - clickToNavLabel = new javax.swing.JLabel(); + viewInTimelineBtn = new javax.swing.JButton(); javax.swing.Box.Filler filler5 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 32767)); mainContentPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10)); @@ -263,8 +312,14 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { last30DaysPanel.setVerifyInputWhenFocusTarget(false); mainContentPanel.add(last30DaysPanel); - org.openide.awt.Mnemonics.setLocalizedText(clickToNavLabel, org.openide.util.NbBundle.getMessage(TimelinePanel.class, "TimelinePanel.clickToNavLabel.text")); // NOI18N - mainContentPanel.add(clickToNavLabel); + org.openide.awt.Mnemonics.setLocalizedText(viewInTimelineBtn, org.openide.util.NbBundle.getMessage(TimelinePanel.class, "TimelinePanel.viewInTimelineBtn.text")); // NOI18N + viewInTimelineBtn.setEnabled(false); + viewInTimelineBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + viewInTimelineBtnActionPerformed(evt); + } + }); + mainContentPanel.add(viewInTimelineBtn); filler5.setAlignmentX(0.0F); mainContentPanel.add(filler5); @@ -283,29 +338,11 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { ); }// //GEN-END:initComponents - private void setupChartClickListener() { - this.last30DaysChart.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); - this.last30DaysChart.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - - TimelinePanel.this.notifyParentClose(); - openTimelineAction.performAction(); - try { - TimeLineController controller = TimeLineModule.getController(); - DataSource dataSource = getDataSource(); - if (dataSource != null) { - controller.pushFilters(timelineUtils.getDataSourceFilterState(dataSource)); - } - } catch (NoCurrentCaseException | TskCoreException ex) { - logger.log(Level.WARNING, "Unable to open Timeline view", ex); - } - } - }); - } - + private void viewInTimelineBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_viewInTimelineBtnActionPerformed + openFilteredChart(); + }//GEN-LAST:event_viewInTimelineBtnActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JLabel clickToNavLabel; + private javax.swing.JButton viewInTimelineBtn; // End of variables declaration//GEN-END:variables } From 47b61790d33701f161f89828607aed912d0dd6c4 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 20 Nov 2020 09:21:37 -0500 Subject: [PATCH 13/42] some small fixes --- .../datamodel/RecentFilesSummary.java | 2 +- .../datasourcesummary/datamodel/TimelineSummary.java | 4 ++-- .../datasourcesummary/ui/Bundle.properties-MERGED | 2 +- .../autopsy/datasourcesummary/ui/TimelinePanel.java | 10 ++++++++-- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummary.java index 5b158e61be..81e44f7db6 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummary.java @@ -298,7 +298,7 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { if (date == null || date == 0 || StringUtils.isBlank(path)) { return null; } else { - return new RecentAttachmentDetails(artifact, path, date, sender); + return new RecentAttachmentDetails(messageArtifact, path, date, sender); } } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummary.java index 46d4a0f827..451e678153 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummary.java @@ -240,7 +240,7 @@ public class TimelineSummary implements DefaultUpdateGovernor { * * @param minDate Earliest usage date recorded for the data source. * @param maxDate Latest usage date recorded for the data source. - * @param recentDaysActivity A list of activity prior to and including + * @param recentDaysActivity A list of activity prior to and including max date sorted by min to max date. * @param dataSource The data source for which this data applies. * the latest usage date by day. */ @@ -267,7 +267,7 @@ public class TimelineSummary implements DefaultUpdateGovernor { /** * @return A list of activity prior to and including the latest usage - * date by day. + * date by day sorted min to max date. */ public List getMostRecentDaysActivity() { return histogramActivity; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED index fc3ebb09cd..5b7a37c275 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED @@ -111,7 +111,7 @@ UserActivityPanel.rightClickForMoreOptions2.text=Right click on row for more opt UserActivityPanel.rightClickForMoreOptions3.text=Right click on row for more options UserActivityPanel.rightClickForMoreOptions4.text=Right click on row for more options UserActivityPanel.rightClickForMoreOptions5.text=Right click on row for more options -TimelinePanel.clickToNavLabel.text=Click to view data source in the timeline +TimelinePanel.viewInTimelineBtn.text=View in Timeline UserActivityPanel_goToArtifact=Go to Artifact UserActivityPanel_goToFile=Go to File UserActivityPanel_noDataExists=No communication data exists diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java index 12da8f60cf..6936ce93bb 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java @@ -211,8 +211,14 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { } dataSource = curTimelineData.getDataSource(); - minDate = curTimelineData.getMinDate(); - maxDate = curTimelineData.getMaxDate(); + if (CollectionUtils.isNotEmpty(curTimelineData.getMostRecentDaysActivity())) { + minDate = curTimelineData.getMostRecentDaysActivity().get(0).getDay(); + maxDate = curTimelineData.getMostRecentDaysActivity().get(curTimelineData.getMostRecentDaysActivity().size() - 1).getDay(); + // set outer bound to end of day instead of beginning + if (maxDate != null) { + maxDate = new Date(maxDate.getTime() + 1000 * 60 * 60 * 24); + } + } } // notify dialog (if in dialog) should close. From 6a136ee28e1c02f784077cd191be6640868af3a1 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 20 Nov 2020 11:11:16 -0500 Subject: [PATCH 14/42] formatting --- .../datamodel/TimelineDataSourceUtils.java | 4 +- .../datamodel/TimelineSummary.java | 34 +++++++++---- .../ui/BaseDataSourceSummaryPanel.java | 4 +- .../ui/DataSourceSummaryDialog.java | 8 +-- .../ui/RecentFilesPanel.form | 12 +++++ .../ui/RecentFilesPanel.java | 9 ++-- .../datasourcesummary/ui/TimelinePanel.java | 17 +++---- .../ui/UserActivityPanel.form | 20 ++++++++ .../ui/UserActivityPanel.java | 16 ++---- .../uiutils/BarChartPanel.java | 40 +-------------- .../uiutils/CellModelTableCellRenderer.java | 19 +++++-- .../uiutils/JTablePanel.java | 50 ++++++++++++++++--- .../datamodel/UserActivitySummaryTest.java | 24 ++++----- 13 files changed, 153 insertions(+), 104 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineDataSourceUtils.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineDataSourceUtils.java index 3e094300bf..40f76cce80 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineDataSourceUtils.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineDataSourceUtils.java @@ -85,9 +85,9 @@ public class TimelineDataSourceUtils { for (FilterState filterState : dataSourceState.getDataSourcesFilterState().getSubFilterStates()) { DataSourceFilter dsFilter = filterState.getFilter(); if (dsFilter != null) { - filterState.setSelected(dsFilter.getDataSourceID() == dataSource.getId()); + filterState.setSelected(dsFilter.getDataSourceID() == dataSource.getId()); } - + } return dataSourceState; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummary.java index 451e678153..a43d46764b 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummary.java @@ -50,11 +50,23 @@ import org.sleuthkit.autopsy.core.UserPreferences; */ public class TimelineSummary implements DefaultUpdateGovernor { - + /** + * A function for obtaining a Timeline RootFilter filtered to the specific + * data source. + */ public interface DataSourceFilterFunction { + + /** + * Obtains a Timeline RootFilter filtered to the specific data source. + * + * @param dataSource The data source. + * @return The timeline root filter. + * @throws NoCurrentCaseException + * @throws TskCoreException + */ RootFilter apply(DataSource dataSource) throws NoCurrentCaseException, TskCoreException; } - + private static final long DAY_SECS = 24 * 60 * 60; private static final Set INGEST_JOB_EVENTS = new HashSet<>( Arrays.asList(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED)); @@ -69,13 +81,13 @@ public class TimelineSummary implements DefaultUpdateGovernor { private final SleuthkitCaseProvider caseProvider; private final Supplier timeZoneProvider; private final DataSourceFilterFunction filterFunction; - + /** * Default constructor. */ public TimelineSummary() { - this(SleuthkitCaseProvider.DEFAULT, - () -> TimeZone.getTimeZone(UserPreferences.getTimeZoneForDisplays()), + this(SleuthkitCaseProvider.DEFAULT, + () -> TimeZone.getTimeZone(UserPreferences.getTimeZoneForDisplays()), (ds) -> TimelineDataSourceUtils.getInstance().getDataSourceFilter(ds)); } @@ -84,7 +96,8 @@ public class TimelineSummary implements DefaultUpdateGovernor { * * @param caseProvider SleuthkitCaseProvider provider; cannot be null. * @param timeZoneProvider The timezone provider; cannot be null. - * @param defaulteStateSupplier Provides the default root filter function filtered to the data source; cannot be null. + * @param filterFunction Provides the default root filter function filtered + * to the data source; cannot be null. */ public TimelineSummary(SleuthkitCaseProvider caseProvider, Supplier timeZoneProvider, DataSourceFilterFunction filterFunction) { this.caseProvider = caseProvider; @@ -193,7 +206,7 @@ public class TimelineSummary implements DefaultUpdateGovernor { * @throws TskCoreException * @throws NoCurrentCaseException */ - private Map getTimelineEventsByDay(DataSource dataSource, TimelineManager timelineManager, TimeZone timeZone) + private Map getTimelineEventsByDay(DataSource dataSource, TimelineManager timelineManager, TimeZone timeZone) throws TskCoreException, NoCurrentCaseException { RootFilter rootFilter = this.filterFunction.apply(dataSource); @@ -240,9 +253,10 @@ public class TimelineSummary implements DefaultUpdateGovernor { * * @param minDate Earliest usage date recorded for the data source. * @param maxDate Latest usage date recorded for the data source. - * @param recentDaysActivity A list of activity prior to and including max date sorted by min to max date. - * @param dataSource The data source for which this data applies. - * the latest usage date by day. + * @param recentDaysActivity A list of activity prior to and including + * max date sorted by min to max date. + * @param dataSource The data source for which this data applies. the + * latest usage date by day. */ TimelineSummaryData(Date minDate, Date maxDate, List recentDaysActivity, DataSource dataSource) { this.minDate = minDate; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java index 155471c18c..62c804db84 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java @@ -271,7 +271,9 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { private static final Pattern windowsDrivePattern = Pattern.compile("^[A-Za-z]\\:(.*)$"); /** - * Normalizes the path for lookup in the sleuthkit database (unix endings; remove C:\). + * Normalizes the path for lookup in the sleuthkit database (unix endings; + * remove C:\). + * * @param path The path to normalize. * @return The normalized path. */ diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryDialog.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryDialog.java index b506437887..97ca3cc6f2 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryDialog.java @@ -40,7 +40,7 @@ import org.sleuthkit.datamodel.IngestJobInfo; * Dialog for displaying the Data Sources Summary information */ final class DataSourceSummaryDialog extends javax.swing.JDialog implements Observer { - + private static final long serialVersionUID = 1L; private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_COMPLETED); private final DataSourceBrowser dataSourcesPanel; @@ -71,7 +71,7 @@ final class DataSourceSummaryDialog extends javax.swing.JDialog implements Obser this.repaint(); } }); - + ingestEventListener = (PropertyChangeEvent evt) -> { if (evt instanceof DataSourceAnalysisCompletedEvent) { DataSourceAnalysisCompletedEvent dsEvent = (DataSourceAnalysisCompletedEvent) evt; @@ -91,7 +91,7 @@ final class DataSourceSummaryDialog extends javax.swing.JDialog implements Obser setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); this.pack(); } - + @Override public void dispose() { IngestManager.getInstance().removeIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, ingestEventListener); @@ -105,7 +105,7 @@ final class DataSourceSummaryDialog extends javax.swing.JDialog implements Obser void enableObserver() { dataSourcesPanel.addObserver(this); } - + @Override public void update(Observable o, Object arg) { this.dispose(); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.form index 8a8ae70a58..77e6cd8262 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.form @@ -166,6 +166,10 @@ + + + + @@ -178,6 +182,10 @@ + + + + @@ -190,6 +198,10 @@ + + + + diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java index db708af9ec..2f94f2d598 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java @@ -278,9 +278,9 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { javax.swing.JLabel openDocsLabel = new javax.swing.JLabel(); javax.swing.JLabel downloadLabel = new javax.swing.JLabel(); javax.swing.JLabel attachmentLabel = new javax.swing.JLabel(); - rightClickForMoreOptions1 = new javax.swing.JLabel(); - rightClickForMoreOptions2 = new javax.swing.JLabel(); - rightClickForMoreOptions3 = new javax.swing.JLabel(); + javax.swing.JLabel rightClickForMoreOptions1 = new javax.swing.JLabel(); + javax.swing.JLabel rightClickForMoreOptions2 = new javax.swing.JLabel(); + javax.swing.JLabel rightClickForMoreOptions3 = new javax.swing.JLabel(); setLayout(new java.awt.BorderLayout()); @@ -386,8 +386,5 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { private javax.swing.JPanel attachmentsPane; private javax.swing.JPanel downloadsPane; private javax.swing.JPanel openedDocPane; - private javax.swing.JLabel rightClickForMoreOptions1; - private javax.swing.JLabel rightClickForMoreOptions2; - private javax.swing.JLabel rightClickForMoreOptions3; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java index 6936ce93bb..490df9a481 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java @@ -163,7 +163,7 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { new BarChartSeries(Bundle.TimlinePanel_last30DaysChart_fileEvts_title(), FILE_EVT_COLOR, fileEvtCounts), new BarChartSeries(Bundle.TimlinePanel_last30DaysChart_artifactEvts_title(), ARTIFACT_EVT_COLOR, artifactEvtCounts)); } - + private final Object timelineBtnLock = new Object(); private TimelineSummaryData curTimelineData = null; @@ -183,10 +183,10 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { if (result != null && result.getResultType() == DataFetchResult.ResultType.SUCCESS && result.getData() != null) { - + synchronized (this.timelineBtnLock) { this.curTimelineData = result.getData(); - this.viewInTimelineBtn.setEnabled(true); + this.viewInTimelineBtn.setEnabled(true); } } else { synchronized (this.timelineBtnLock) { @@ -202,14 +202,13 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { DataSource dataSource = null; Date minDate = null; Date maxDate = null; - // get date from current timelineData if that data exists. synchronized (this.timelineBtnLock) { if (curTimelineData == null) { return; } - + dataSource = curTimelineData.getDataSource(); if (CollectionUtils.isNotEmpty(curTimelineData.getMostRecentDaysActivity())) { minDate = curTimelineData.getMostRecentDaysActivity().get(0).getDay(); @@ -220,10 +219,10 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { } } } - + // notify dialog (if in dialog) should close. TimelinePanel.this.notifyParentClose(); - + // open the timeline filtered to data source and zoomed in on interval openTimelineAction.performAction(); try { @@ -231,12 +230,12 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { if (dataSource != null) { controller.pushFilters(timelineUtils.getDataSourceFilterState(dataSource)); } - + if (minDate != null && maxDate != null) { Interval timeSpan = new Interval(new DateTime(minDate), new DateTime(maxDate)); controller.pushTimeRange(timeSpan); } - + } catch (NoCurrentCaseException | TskCoreException ex) { logger.log(Level.WARNING, "Unable to open Timeline view", ex); } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.form index a1a04bbe17..f3920eeba0 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.form @@ -141,6 +141,10 @@ + + + + @@ -217,6 +221,10 @@ + + + + @@ -293,6 +301,10 @@ + + + + @@ -369,6 +381,10 @@ + + + + @@ -445,6 +461,10 @@ + + + + diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java index afac5607e9..68ff255b0c 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java @@ -41,7 +41,6 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetch import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel.ColumnModel; -import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.DataSource; /** @@ -386,27 +385,27 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { javax.swing.JLabel programsRunLabel = new javax.swing.JLabel(); javax.swing.Box.Filler filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2)); javax.swing.JPanel topProgramsTablePanel = topProgramsTable; - rightClickForMoreOptions1 = new javax.swing.JLabel(); + javax.swing.JLabel rightClickForMoreOptions1 = new javax.swing.JLabel(); javax.swing.Box.Filler filler3 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20)); javax.swing.JLabel recentDomainsLabel = new javax.swing.JLabel(); javax.swing.Box.Filler filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2)); javax.swing.JPanel recentDomainsTablePanel = recentDomainsTable; - rightClickForMoreOptions2 = new javax.swing.JLabel(); + javax.swing.JLabel rightClickForMoreOptions2 = new javax.swing.JLabel(); javax.swing.Box.Filler filler4 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20)); javax.swing.JLabel topWebSearchLabel = new javax.swing.JLabel(); javax.swing.Box.Filler filler5 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2)); javax.swing.JPanel topWebSearches = topWebSearchesTable; - rightClickForMoreOptions3 = new javax.swing.JLabel(); + javax.swing.JLabel rightClickForMoreOptions3 = new javax.swing.JLabel(); javax.swing.Box.Filler filler6 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20)); javax.swing.JLabel topDevicesAttachedLabel = new javax.swing.JLabel(); javax.swing.Box.Filler filler7 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2)); javax.swing.JPanel recentDevicesAttached = topDevicesAttachedTable; - rightClickForMoreOptions4 = new javax.swing.JLabel(); + javax.swing.JLabel rightClickForMoreOptions4 = new javax.swing.JLabel(); javax.swing.Box.Filler filler8 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20)); javax.swing.JLabel recentAccountsLabel = new javax.swing.JLabel(); javax.swing.Box.Filler filler9 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2)); javax.swing.JPanel topAccounts = topAccountsTable; - rightClickForMoreOptions5 = new javax.swing.JLabel(); + javax.swing.JLabel rightClickForMoreOptions5 = new javax.swing.JLabel(); setLayout(new java.awt.BorderLayout()); @@ -505,10 +504,5 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JLabel rightClickForMoreOptions1; - private javax.swing.JLabel rightClickForMoreOptions2; - private javax.swing.JLabel rightClickForMoreOptions3; - private javax.swing.JLabel rightClickForMoreOptions4; - private javax.swing.JLabel rightClickForMoreOptions5; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/BarChartPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/BarChartPanel.java index 6e1db485f5..88ab51d563 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/BarChartPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/BarChartPanel.java @@ -21,12 +21,9 @@ package org.sleuthkit.autopsy.datasourcesummary.uiutils; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Font; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; import java.util.Collections; import java.util.List; import javax.swing.JLabel; -import javax.swing.JPanel; import org.apache.commons.collections4.CollectionUtils; import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartPanel; @@ -255,44 +252,10 @@ public class BarChartPanel extends AbstractLoadableComponent> menuItemSupplier) { this.menuItemSupplier = menuItemSupplier; @@ -329,6 +332,10 @@ public class CellModelTableCellRenderer extends DefaultTableCellRenderer { return defaultCell; } + /** + * The default cell mouse listener that triggers popups for non-primary + * button events. + */ private static final CellMouseListener DEFAULT_CELL_MOUSE_LISTENER = new CellMouseListener() { @Override @@ -355,6 +362,10 @@ public class CellModelTableCellRenderer extends DefaultTableCellRenderer { } }; + /** + * @return The default cell mouse listener that triggers popups for + * non-primary button events. + */ public static CellMouseListener getMouseListener() { return DEFAULT_CELL_MOUSE_LISTENER; } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/JTablePanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/JTablePanel.java index ec055a42b9..3f694d78c9 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/JTablePanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/JTablePanel.java @@ -42,13 +42,27 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRendere */ public class JTablePanel extends AbstractLoadableComponent> { + /** + * An event that wraps a swing MouseEvent also providing context within the + * table cell. + */ public static class CellMouseEvent { + private final MouseEvent e; private final JTable table; private final int row; private final int col; private final Object cellValue; + /** + * Main constructor. + * + * @param e The underlying mouse event. + * @param table The table that was the target of the mouse event. + * @param row The row within the table that the event occurs. + * @param col The column within the table that the event occurs. + * @param cellValue The value within the cell. + */ public CellMouseEvent(MouseEvent e, JTable table, int row, int col, Object cellValue) { this.e = e; this.table = table; @@ -57,27 +71,42 @@ public class JTablePanel extends AbstractLoadableComponent> { this.cellValue = cellValue; } + /** + * @return The underlying mouse event. + */ public MouseEvent getMouseEvent() { return e; } + /** + * @return The table that was the target of the mouse event. + */ public JTable getTable() { return table; } + /** + * @return The row within the table that the event occurs. + */ public int getRow() { return row; } + /** + * @return The column within the table that the event occurs. + */ public int getCol() { return col; } + /** + * @return The value within the cell. + */ public Object getCellValue() { return cellValue; } } - + /** * Handles mouse events for cells in the table. */ @@ -86,7 +115,8 @@ public class JTablePanel extends AbstractLoadableComponent> { /** * Handles mouse events at a cell level for the table. * - * @param e The event containing information about the cell, the mouse event, and the table. + * @param e The event containing information about the cell, the mouse + * event, and the table. */ void mouseClicked(CellMouseEvent e); } @@ -251,7 +281,7 @@ public class JTablePanel extends AbstractLoadableComponent> { JTablePanel resultTable = new JTablePanel<>(tableModel) .setColumnModel(getTableColumnModel(columns)) .setCellListener(CellModelTableCellRenderer.getMouseListener()); - + return resultTable; } @@ -317,17 +347,25 @@ public class JTablePanel extends AbstractLoadableComponent> { return this; } - + /** + * @return The current listener for mouse events. The events provided to + * this listener will have cell and table context. + */ public CellMouseListener getCellListener() { return cellListener; } + /** + * Sets the current listener for mouse events. + * + * @param cellListener The event listener that will receive these events + * with cell and table context. + * @return + */ public JTablePanel setCellListener(CellMouseListener cellListener) { this.cellListener = cellListener; return this; } - - /** * @return The underlying JTable's column model. diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java index 3c62dc95b1..47bdf71fc8 100644 --- a/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java @@ -353,7 +353,7 @@ public class UserActivitySummaryTest { List results = summary.getRecentDevices(dataSource, 10); Assert.assertEquals(1, results.size()); - Assert.assertEquals((long) (DAY_SECONDS + 2), results.get(0).getDateAccessed().getTime() / 1000); + Assert.assertEquals((long) (DAY_SECONDS + 2), results.get(0).getLastAccessed().getTime() / 1000); Assert.assertTrue("ID1".equalsIgnoreCase(results.get(0).getDeviceId())); Assert.assertTrue("MAKE1".equalsIgnoreCase(results.get(0).getDeviceMake())); Assert.assertTrue("MODEL1".equalsIgnoreCase(results.get(0).getDeviceModel())); @@ -896,13 +896,13 @@ public class UserActivitySummaryTest { getRecentAccountsOneArtTest(ds1, email1, new TopAccountResult( Bundle.DataSourceUserActivitySummary_getRecentAccounts_emailMessage(), - new Date(DAY_SECONDS * 1000))); + new Date(DAY_SECONDS * 1000), email1)); BlackboardArtifact email2 = getEmailArtifact(2, ds1, null, DAY_SECONDS); getRecentAccountsOneArtTest(ds1, email2, new TopAccountResult( Bundle.DataSourceUserActivitySummary_getRecentAccounts_emailMessage(), - new Date(DAY_SECONDS * 1000))); + new Date(DAY_SECONDS * 1000), email2)); BlackboardArtifact email3 = getEmailArtifact(3, ds1, null, null); getRecentAccountsOneArtTest(ds1, email3, null); @@ -911,19 +911,19 @@ public class UserActivitySummaryTest { getRecentAccountsOneArtTest(ds1, email4, new TopAccountResult( Bundle.DataSourceUserActivitySummary_getRecentAccounts_emailMessage(), - new Date(DAY_SECONDS * 2 * 1000))); + new Date(DAY_SECONDS * 2 * 1000), email4)); BlackboardArtifact callog1 = getCallogArtifact(11, ds1, DAY_SECONDS, null); getRecentAccountsOneArtTest(ds1, callog1, new TopAccountResult( Bundle.DataSourceUserActivitySummary_getRecentAccounts_calllogMessage(), - new Date(DAY_SECONDS * 1000))); + new Date(DAY_SECONDS * 1000), callog1)); BlackboardArtifact callog2 = getCallogArtifact(12, ds1, null, DAY_SECONDS); getRecentAccountsOneArtTest(ds1, callog2, new TopAccountResult( Bundle.DataSourceUserActivitySummary_getRecentAccounts_calllogMessage(), - new Date(DAY_SECONDS * 1000))); + new Date(DAY_SECONDS * 1000), callog2)); BlackboardArtifact callog3 = getCallogArtifact(13, ds1, null, null); getRecentAccountsOneArtTest(ds1, callog3, null); @@ -932,7 +932,7 @@ public class UserActivitySummaryTest { getRecentAccountsOneArtTest(ds1, callog4, new TopAccountResult( Bundle.DataSourceUserActivitySummary_getRecentAccounts_calllogMessage(), - new Date(DAY_SECONDS * 2 * 1000))); + new Date(DAY_SECONDS * 2 * 1000), callog4)); BlackboardArtifact message1 = getMessageArtifact(21, ds1, "Skype", null); getRecentAccountsOneArtTest(ds1, message1, null); @@ -944,7 +944,7 @@ public class UserActivitySummaryTest { getRecentAccountsOneArtTest(ds1, message3, null); BlackboardArtifact message4 = getMessageArtifact(24, ds1, "Skype", DAY_SECONDS); - getRecentAccountsOneArtTest(ds1, message4, new TopAccountResult("Skype", new Date(DAY_SECONDS * 1000))); + getRecentAccountsOneArtTest(ds1, message4, new TopAccountResult("Skype", new Date(DAY_SECONDS * 1000), message4)); } @@ -977,10 +977,10 @@ public class UserActivitySummaryTest { getRecentAccountsTest(ds1, 10, Arrays.asList(email1, email2, email3, callog1, callog2, message1a, message1b, message2a, message2b), Arrays.asList( - new TopAccountResult("Facebook", new Date((DAY_SECONDS + 42) * 1000)), - new TopAccountResult("Skype", new Date((DAY_SECONDS + 32) * 1000)), - new TopAccountResult(Bundle.DataSourceUserActivitySummary_getRecentAccounts_calllogMessage(), new Date((DAY_SECONDS + 22) * 1000)), - new TopAccountResult(Bundle.DataSourceUserActivitySummary_getRecentAccounts_emailMessage(), new Date((DAY_SECONDS + 13) * 1000)) + new TopAccountResult("Facebook", new Date((DAY_SECONDS + 42) * 1000), message2b), + new TopAccountResult("Skype", new Date((DAY_SECONDS + 32) * 1000), message1b), + new TopAccountResult(Bundle.DataSourceUserActivitySummary_getRecentAccounts_calllogMessage(), new Date((DAY_SECONDS + 22) * 1000), callog2), + new TopAccountResult(Bundle.DataSourceUserActivitySummary_getRecentAccounts_emailMessage(), new Date((DAY_SECONDS + 13) * 1000), email3) )); } From 27c6283959e257e52b2dafb8ec4e72f0258028c5 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 20 Nov 2020 11:20:30 -0500 Subject: [PATCH 15/42] formatting --- .../datasourcesummary/datamodel/UserActivitySummaryTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java index 47bdf71fc8..572d4f86b3 100644 --- a/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java @@ -870,6 +870,7 @@ public class UserActivitySummaryTest { // since this may be somewhat variable Assert.assertTrue(expectedItem.getAccountType().equalsIgnoreCase(receivedItem.getAccountType())); Assert.assertEquals(expectedItem.getLastAccessed().getTime(), receivedItem.getLastAccessed().getTime()); + Assert.assertEquals(expectedItem.getArtifact(), receivedItem.getArtifact()); } } From e015b93eb571de9e7e4bbce456715121724a211c Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 23 Nov 2020 13:32:49 -0500 Subject: [PATCH 16/42] timeline time range fix --- .../datasourcesummary/ui/TimelinePanel.java | 71 ++++++++++++------- .../autopsy/timeline/OpenTimelineAction.java | 42 +++++++---- .../autopsy/timeline/TimeLineController.java | 26 +++---- 3 files changed, 86 insertions(+), 53 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java index 490df9a481..cd56754579 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java @@ -31,6 +31,7 @@ import org.apache.commons.collections.CollectionUtils; import org.joda.time.DateTime; import org.joda.time.Interval; import org.openide.util.NbBundle.Messages; +import org.openide.util.actions.CallableSystemAction; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineDataSourceUtils; @@ -64,7 +65,7 @@ import org.sleuthkit.datamodel.TskCoreException; "TimlinePanel_last30DaysChart_fileEvts_title=File Events", "TimlinePanel_last30DaysChart_artifactEvts_title=Artifact Events",}) public class TimelinePanel extends BaseDataSourceSummaryPanel { - + private static final Logger logger = Logger.getLogger(TimelinePanel.class.getName()); private static final long serialVersionUID = 1L; private static final DateFormat EARLIEST_LATEST_FORMAT = getUtcFormat("MMM d, yyyy"); @@ -86,7 +87,6 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { private final LoadableLabel earliestLabel = new LoadableLabel(Bundle.TimelinePanel_earliestLabel_title()); private final LoadableLabel latestLabel = new LoadableLabel(Bundle.TimelinePanel_latestLabel_title()); private final BarChartPanel last30DaysChart = new BarChartPanel(Bundle.TimlinePanel_last30DaysChart_title(), "", ""); - private final OpenTimelineAction openTimelineAction = new OpenTimelineAction(); private final TimelineDataSourceUtils timelineUtils = TimelineDataSourceUtils.getInstance(); // all loadable components on this tab @@ -94,7 +94,7 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { // actions to load data for this tab private final List> dataFetchComponents; - + public TimelinePanel() { this(new TimelineSummary()); } @@ -109,7 +109,7 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { (dataSource) -> timelineData.getData(dataSource, MOST_RECENT_DAYS_COUNT), (result) -> handleResult(result)) ); - + initComponents(); } @@ -125,7 +125,7 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { private static String formatDate(Date date, DateFormat formatter) { return date == null ? null : formatter.format(date); } - + private static final Color FILE_EVT_COLOR = new Color(228, 22, 28); private static final Color ARTIFACT_EVT_COLOR = new Color(21, 227, 100); @@ -145,25 +145,25 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { // Create a bar chart item for each recent days activity item List fileEvtCounts = new ArrayList<>(); List artifactEvtCounts = new ArrayList<>(); - + for (int i = 0; i < recentDaysActivity.size(); i++) { DailyActivityAmount curItem = recentDaysActivity.get(i); - + long fileAmt = curItem.getFileActivityCount(); long artifactAmt = curItem.getArtifactActivityCount() * 100; String formattedDate = (i == 0 || i == recentDaysActivity.size() - 1) ? formatDate(curItem.getDay(), CHART_FORMAT) : ""; - + OrderedKey thisKey = new OrderedKey(formattedDate, i); fileEvtCounts.add(new BarChartItem(thisKey, fileAmt)); artifactEvtCounts.add(new BarChartItem(thisKey, artifactAmt)); } - + return Arrays.asList( new BarChartSeries(Bundle.TimlinePanel_last30DaysChart_fileEvts_title(), FILE_EVT_COLOR, fileEvtCounts), new BarChartSeries(Bundle.TimlinePanel_last30DaysChart_artifactEvts_title(), ARTIFACT_EVT_COLOR, artifactEvtCounts)); } - + private final Object timelineBtnLock = new Object(); private TimelineSummaryData curTimelineData = null; @@ -179,11 +179,11 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { earliestLabel.showDataFetchResult(DataFetchResult.getSubResult(result, r -> formatDate(r.getMinDate(), EARLIEST_LATEST_FORMAT))); latestLabel.showDataFetchResult(DataFetchResult.getSubResult(result, r -> formatDate(r.getMaxDate(), EARLIEST_LATEST_FORMAT))); last30DaysChart.showDataFetchResult(DataFetchResult.getSubResult(result, r -> parseChartData(r.getMostRecentDaysActivity()))); - + if (result != null && result.getResultType() == DataFetchResult.ResultType.SUCCESS && result.getData() != null) { - + synchronized (this.timelineBtnLock) { this.curTimelineData = result.getData(); this.viewInTimelineBtn.setEnabled(true); @@ -208,7 +208,7 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { if (curTimelineData == null) { return; } - + dataSource = curTimelineData.getDataSource(); if (CollectionUtils.isNotEmpty(curTimelineData.getMostRecentDaysActivity())) { minDate = curTimelineData.getMostRecentDaysActivity().get(0).getDay(); @@ -219,38 +219,59 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { } } } + + openFilteredChart(dataSource, minDate, maxDate); + } + + /** + * Action that occurs when 'View in Timeline' button is pressed. + * + * @param dataSource The data source to filter to. + * @param minDate The min date for the zoom of the window. + * @param maxDate The max date for the zoom of the window. + */ + private void openFilteredChart(DataSource dataSource, Date minDate, Date maxDate) { + OpenTimelineAction openTimelineAction = CallableSystemAction.get(OpenTimelineAction.class); + if (openTimelineAction == null) { + logger.log(Level.WARNING, "No OpenTimelineAction provided by CallableSystemAction; taking no redirect action."); + } // notify dialog (if in dialog) should close. TimelinePanel.this.notifyParentClose(); - - // open the timeline filtered to data source and zoomed in on interval - openTimelineAction.performAction(); + + Interval timeSpan = null; + try { - TimeLineController controller = TimeLineModule.getController(); + final TimeLineController controller = TimeLineModule.getController(); + if (dataSource != null) { controller.pushFilters(timelineUtils.getDataSourceFilterState(dataSource)); } - + if (minDate != null && maxDate != null) { - Interval timeSpan = new Interval(new DateTime(minDate), new DateTime(maxDate)); - controller.pushTimeRange(timeSpan); + timeSpan = new Interval(new DateTime(minDate), new DateTime(maxDate)); } - } catch (NoCurrentCaseException | TskCoreException ex) { - logger.log(Level.WARNING, "Unable to open Timeline view", ex); + logger.log(Level.WARNING, "Unable to view time range in Timeline view", ex); + } + + try { + openTimelineAction.showTimeline(timeSpan); + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "An unexpected exception occurred while opening the timeline.", ex); } } - + @Override protected void fetchInformation(DataSource dataSource) { fetchInformation(dataFetchComponents, dataSource); } - + @Override protected void onNewDataSource(DataSource dataSource) { onNewDataSource(dataFetchComponents, loadableComponents, dataSource); } - + @Override public void close() { ingestRunningLabel.unregister(); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java b/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java index 202e521dc2..fdd45d14a1 100755 --- a/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java @@ -24,6 +24,7 @@ import javafx.application.Platform; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JMenuItem; +import org.joda.time.Interval; import org.openide.awt.ActionID; import org.openide.awt.ActionReference; import org.openide.awt.ActionReferences; @@ -46,13 +47,10 @@ import org.sleuthkit.datamodel.TskCoreException; * An Action that opens the Timeline window. Has methods to open the window in * various specific states (e.g., showing a specific artifact in the List View) */ - - @ActionID(category = "Tools", id = "org.sleuthkit.autopsy.timeline.Timeline") @ActionRegistration(displayName = "#CTL_MakeTimeline", lazy = false) @ActionReferences(value = { - @ActionReference(path = "Menu/Tools", position = 104) - , + @ActionReference(path = "Menu/Tools", position = 104), @ActionReference(path = "Toolbars/Case", position = 104)}) public final class OpenTimelineAction extends CallableSystemAction { @@ -64,7 +62,6 @@ public final class OpenTimelineAction extends CallableSystemAction { private final JButton toolbarButton = new JButton(getName(), new ImageIcon(getClass().getResource("images/btn_icon_timeline_colorized_26.png"))); //NON-NLS - public OpenTimelineAction() { toolbarButton.addActionListener(actionEvent -> performAction()); menuItem = super.getMenuPresenter(); @@ -74,9 +71,10 @@ public final class OpenTimelineAction extends CallableSystemAction { @Override public boolean isEnabled() { /** - * We used to also check if Case.getCurrentOpenCase().hasData() was true. We - * disabled that check because if it is executed while a data source is - * being added, it blocks the edt. We still do that in ImageGallery. + * We used to also check if Case.getCurrentOpenCase().hasData() was + * true. We disabled that check because if it is executed while a data + * source is being added, it blocks the edt. We still do that in + * ImageGallery. */ return super.isEnabled() && Case.isCaseOpen() && Installer.isJavaFxInited(); } @@ -103,7 +101,7 @@ public final class OpenTimelineAction extends CallableSystemAction { @NbBundle.Messages({ "OpenTimelineAction.settingsErrorMessage=Failed to initialize timeline settings.", "OpenTimeLineAction.msgdlg.text=Could not create timeline, there are no data sources."}) - synchronized private void showTimeline(AbstractFile file, BlackboardArtifact artifact) throws TskCoreException { + synchronized private void showTimeline(AbstractFile file, BlackboardArtifact artifact, Interval timeSpan) throws TskCoreException { try { Case currentCase = Case.getCurrentCaseThrows(); if (currentCase.hasData() == false) { @@ -112,6 +110,15 @@ public final class OpenTimelineAction extends CallableSystemAction { return; } TimeLineController controller = TimeLineModule.getController(); + // if file or artifact not specified, specify the time range as either + // a) full range if timeSpan is null or b) the timeSpan + if (file == null && artifact == null) { + if (timeSpan == null) { + controller.showFullRange(); + } else { + controller.pushTimeRange(timeSpan); + } + } controller.showTimeLine(file, artifact); } catch (NoCurrentCaseException e) { //there is no case... Do nothing. @@ -123,7 +130,18 @@ public final class OpenTimelineAction extends CallableSystemAction { */ @ThreadConfined(type = ThreadConfined.ThreadType.AWT) public void showTimeline() throws TskCoreException { - showTimeline(null, null); + showTimeline(null, null, null); + } + + /** + * Open timeline with the given timeSpan time range. + * + * @param timeSpan The time range to display. + * @throws TskCoreException + */ + @ThreadConfined(type = ThreadConfined.ThreadType.AWT) + public void showTimeline(Interval timeSpan) throws TskCoreException { + showTimeline(null, null, timeSpan); } /** @@ -135,7 +153,7 @@ public final class OpenTimelineAction extends CallableSystemAction { */ @ThreadConfined(type = ThreadConfined.ThreadType.AWT) public void showFileInTimeline(AbstractFile file) throws TskCoreException { - showTimeline(file, null); + showTimeline(file, null, null); } /** @@ -146,7 +164,7 @@ public final class OpenTimelineAction extends CallableSystemAction { */ @ThreadConfined(type = ThreadConfined.ThreadType.AWT) public void showArtifactInTimeline(BlackboardArtifact artifact) throws TskCoreException { - showTimeline(null, artifact); + showTimeline(null, artifact, null); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/timeline/TimeLineController.java b/Core/src/org/sleuthkit/autopsy/timeline/TimeLineController.java index 0c80cb5315..80dba865f5 100755 --- a/Core/src/org/sleuthkit/autopsy/timeline/TimeLineController.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/TimeLineController.java @@ -62,7 +62,6 @@ import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; -import static org.sleuthkit.autopsy.casemodule.Case.Events.CURRENT_CASE; import static org.sleuthkit.autopsy.casemodule.Case.Events.DATA_SOURCE_ADDED; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagAddedEvent; @@ -348,7 +347,7 @@ public class TimeLineController { /** * Show the entire range of the timeline. */ - private boolean showFullRange() throws TskCoreException { + boolean showFullRange() throws TskCoreException { synchronized (filteredEvents) { return pushTimeRange(filteredEvents.getSpanningInterval()); } @@ -359,7 +358,7 @@ public class TimeLineController { * ViewInTimelineRequestedEvent in the List View. * * @param requestEvent Contains the ID of the requested events and the - * timerange to show. + * timerange to show. */ @ThreadConfined(type = ThreadConfined.ThreadType.JFX) private void showInListView(ViewInTimelineRequestedEvent requestEvent) throws TskCoreException { @@ -376,14 +375,13 @@ public class TimeLineController { } } - /** * Shuts down the task executor in charge of handling case events. */ void shutDownTimeLineListeners() { ThreadUtils.shutDownTaskExecutor(executor); } - + /** * "Shut down" Timeline. Close the timeline window. */ @@ -394,15 +392,13 @@ public class TimeLineController { topComponent = null; } } - - /** * Add the case and ingest listeners, prompt for rebuilding the database if * necessary, and show the timeline window. * - * @param file The AbstractFile from which to choose an event to show in - * the List View. + * @param file The AbstractFile from which to choose an event to show in the + * List View. * @param artifact The BlackboardArtifact to show in the List View. */ @ThreadConfined(type = ThreadConfined.ThreadType.AWT) @@ -421,9 +417,7 @@ public class TimeLineController { try { if (file == null && artifact == null) { SwingUtilities.invokeLater(TimeLineController.this::showWindow); - this.showFullRange(); } else { - //prompt user to pick specific event and time range ShowInTimelineDialog showInTimelineDilaog = (file == null) ? new ShowInTimelineDialog(this, artifact) @@ -453,7 +447,7 @@ public class TimeLineController { * around the middle of the currently viewed time range. * * @param period The period of time to show around the current center of the - * view. + * view. */ synchronized public void pushPeriod(ReadablePeriod period) throws TskCoreException { synchronized (filteredEvents) { @@ -496,8 +490,8 @@ public class TimeLineController { */ topComponent.requestActive(); } - - synchronized public TimeLineTopComponent getTopComponent(){ + + synchronized public TimeLineTopComponent getTopComponent() { return topComponent; } @@ -517,7 +511,7 @@ public class TimeLineController { * @param timeRange The Interval to view. * * @return True if the interval was changed. False if the interval was the - * same as the existing one and no change happened. + * same as the existing one and no change happened. */ synchronized public boolean pushTimeRange(Interval timeRange) throws TskCoreException { //clamp timerange to case @@ -709,7 +703,7 @@ public class TimeLineController { * Register the given object to receive events. * * @param listener The object to register. Must implement public methods - * annotated with Subscribe. + * annotated with Subscribe. */ synchronized public void registerForEvents(Object listener) { eventbus.register(listener); From 98f3d2a974d96a35314e74b928f03a7e14a318d3 Mon Sep 17 00:00:00 2001 From: apriestman Date: Tue, 24 Nov 2020 08:22:17 -0500 Subject: [PATCH 17/42] Add support for GPS area artifacts --- .../autopsy/datamodel/utils/IconsUtil.java | 2 + .../geolocation/AbstractWaypointFetcher.java | 79 ++++++-- .../autopsy/geolocation/GeoFilterPanel.java | 4 +- .../geolocation/GeolocationTopComponent.java | 11 +- .../autopsy/geolocation/MapPanel.java | 120 +++++++++++- .../autopsy/geolocation/MapWaypoint.java | 1 + .../autopsy/geolocation/datamodel/Area.java | 177 ++++++++++++++++++ .../datamodel/Bundle.properties-MERGED | 2 + .../geolocation/datamodel/GeoPath.java | 38 +++- .../datamodel/WaypointBuilder.java | 22 +++ .../org/sleuthkit/autopsy/images/gps-area.png | Bin 0 -> 984 bytes .../autopsy/ingest/Bundle.properties-MERGED | 2 + .../infrastructure/TableReportGenerator.java | 1 + .../report/modules/html/HTMLReport.java | 3 + .../modules/kml/Bundle.properties-MERGED | 1 + .../autopsy/report/modules/kml/KMLReport.java | 104 +++++++++- 16 files changed, 534 insertions(+), 33 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Area.java create mode 100644 Core/src/org/sleuthkit/autopsy/images/gps-area.png diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/utils/IconsUtil.java b/Core/src/org/sleuthkit/autopsy/datamodel/utils/IconsUtil.java index 5a22888a2f..33291f3224 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/utils/IconsUtil.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/utils/IconsUtil.java @@ -121,6 +121,8 @@ public final class IconsUtil { imageFile = "web-account-type.png"; //NON-NLS } else if (typeID == ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS.getTypeID()) { imageFile = "web-form-address.png"; //NON-NLS + } else if (typeID == ARTIFACT_TYPE.TSK_GPS_AREA.getTypeID()) { + imageFile = "gps-area.png"; //NON-NLS } else { imageFile = "artifact-icon.png"; //NON-NLS } diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/AbstractWaypointFetcher.java b/Core/src/org/sleuthkit/autopsy/geolocation/AbstractWaypointFetcher.java index fccdfacd29..955eb3dba7 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/AbstractWaypointFetcher.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/AbstractWaypointFetcher.java @@ -22,11 +22,11 @@ import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.logging.Level; -import javafx.util.Pair; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationDataException; import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationParseResult; +import org.sleuthkit.autopsy.geolocation.datamodel.Area; import org.sleuthkit.autopsy.geolocation.datamodel.Track; import org.sleuthkit.autopsy.geolocation.datamodel.Waypoint; import org.sleuthkit.autopsy.geolocation.datamodel.WaypointBuilder; @@ -81,7 +81,7 @@ abstract class AbstractWaypointFetcher implements WaypointBuilder.WaypointFilter * @param wasEntirelySuccessful True if no errors occurred while processing. */ abstract void handleFilteredWaypointSet(Set mapWaypoints, List> tracks, - boolean wasEntirelySuccessful); + List> areas, boolean wasEntirelySuccessful); @Override public void process(GeoLocationParseResult waypointResults) { @@ -93,36 +93,54 @@ abstract class AbstractWaypointFetcher implements WaypointBuilder.WaypointFilter logger.log(Level.WARNING, "Exception thrown while retrieving list of Tracks", ex); } } - - Pair, List>> waypointsAndTracks = createWaypointList( + + GeoLocationParseResult areaResults = null; + if (filters.getArtifactTypes().contains(ARTIFACT_TYPE.TSK_GPS_AREA)) { + try { + areaResults = Area.getAreas(Case.getCurrentCase().getSleuthkitCase(), filters.getDataSources()); + } catch (GeoLocationDataException ex) { + logger.log(Level.WARNING, "Exception thrown while retrieving list of Areas", ex); + } + } + + GeoDataSet geoDataSet = createWaypointList( waypointResults.getItems(), - (trackResults == null) ? new ArrayList() : trackResults.getItems()); + (trackResults == null) ? new ArrayList<>() : trackResults.getItems(), + (areaResults == null) ? new ArrayList<>() : areaResults.getItems()); - final Set pointSet = MapWaypoint.getWaypoints(waypointsAndTracks.getKey()); + final Set pointSet = MapWaypoint.getWaypoints(geoDataSet.getWaypoints()); final List> trackSets = new ArrayList<>(); - for (List t : waypointsAndTracks.getValue()) { + for (List t : geoDataSet.getTracks()) { trackSets.add(MapWaypoint.getWaypoints(t)); } - + final List> areaSets = new ArrayList<>(); + for (List t : geoDataSet.getAreas()) { + areaSets.add(MapWaypoint.getWaypoints(t)); + } + // TODO check for area errors too TODO TODO handleFilteredWaypointSet( - pointSet, trackSets, - (trackResults == null || trackResults.isSuccessfullyParsed()) && waypointResults.isSuccessfullyParsed()); + pointSet, trackSets, areaSets, + (trackResults == null || trackResults.isSuccessfullyParsed()) + && (areaResults == null || areaResults.isSuccessfullyParsed()) + && waypointResults.isSuccessfullyParsed()); } /** - * Returns a complete list of waypoints including the tracks. Takes into + * Returns a complete list of waypoints including the tracks and areas. Takes into * account the current filters and includes waypoints as approprate. * * @param waypoints List of waypoints * @param tracks List of tracks + * @param areas List of areas * - * @return A list of waypoints including the tracks based on the current - * filters. + * @return A GeoDataSet object containing a list of waypoints including the tracks and areas based on the current + filters. */ - private Pair, List>> createWaypointList(List waypoints, List tracks) { + private GeoDataSet createWaypointList(List waypoints, List tracks, List areas) { final List completeList = new ArrayList<>(); List> filteredTracks = new ArrayList<>(); + List> filteredAreas = new ArrayList<>(); if (tracks != null) { Long timeRangeEnd; @@ -149,7 +167,14 @@ abstract class AbstractWaypointFetcher implements WaypointBuilder.WaypointFilter } else { completeList.addAll(waypoints); } - return new Pair<>(completeList, filteredTracks); + + // Areas don't have timestamps so add all of them + for (Area area : areas) { + completeList.addAll(area.getPath()); + filteredAreas.add(area.getPath()); + } + + return new GeoDataSet(completeList, filteredTracks, filteredAreas); } /** @@ -270,4 +295,28 @@ abstract class AbstractWaypointFetcher implements WaypointBuilder.WaypointFilter return -1L; } + + static class GeoDataSet { + private final List waypoints; + private final List> tracks; + private final List> areas; + + GeoDataSet(List waypoints, List> tracks, List> areas) { + this.waypoints = waypoints; + this.tracks = tracks; + this.areas = areas; + } + + List getWaypoints() { + return waypoints; + } + + List> getTracks() { + return tracks; + } + + List> getAreas() { + return areas; + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java b/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java index df91b2963e..8fe7a70542 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java @@ -71,7 +71,8 @@ class GeoFilterPanel extends javax.swing.JPanel { ARTIFACT_TYPE.TSK_GPS_SEARCH, ARTIFACT_TYPE.TSK_GPS_TRACK, ARTIFACT_TYPE.TSK_GPS_TRACKPOINT, - ARTIFACT_TYPE.TSK_METADATA_EXIF + ARTIFACT_TYPE.TSK_METADATA_EXIF, + ARTIFACT_TYPE.TSK_GPS_AREA }; /** @@ -523,6 +524,7 @@ class GeoFilterPanel extends javax.swing.JPanel { + " or attrs.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID() + " or attrs.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_TRACKPOINTS.getTypeID() + " or attrs.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_WAYPOINTS.getTypeID() + + " or attrs.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_AREAPOINTS.getTypeID() + " )" + " ) as innerTable"; try (SleuthkitCase.CaseDbQuery queryResult = sleuthkitCase.executeQuery(queryStr); diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationTopComponent.java b/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationTopComponent.java index 31ef953fdc..57ea19391c 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationTopComponent.java @@ -115,7 +115,8 @@ public final class GeolocationTopComponent extends TopComponent { || eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_ROUTE.getTypeID() || eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID() || eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_BOOKMARK.getTypeID() - || eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACK.getTypeID())) { + || eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACK.getTypeID() + || eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_AREA.getTypeID())) { showRefreshPanel(true); } @@ -330,7 +331,7 @@ public final class GeolocationTopComponent extends TopComponent { * * @param waypointList */ - void addWaypointsToMap(Set waypointList, List> tracks) { + void addWaypointsToMap(Set waypointList, List> tracks, List> areas) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { @@ -348,6 +349,7 @@ public final class GeolocationTopComponent extends TopComponent { mapPanel.clearWaypoints(); mapPanel.setWaypoints(waypointList); mapPanel.setTracks(tracks); + mapPanel.setAreas(areas); mapPanel.initializePainter(); setWaypointLoading(false); geoFilterPanel.setEnabled(true); @@ -505,8 +507,9 @@ public final class GeolocationTopComponent extends TopComponent { } @Override - void handleFilteredWaypointSet(Set mapWaypoints, List> tracks, boolean wasEntirelySuccessful) { - addWaypointsToMap(mapWaypoints, tracks); + void handleFilteredWaypointSet(Set mapWaypoints, List> tracks, + List> areas, boolean wasEntirelySuccessful) { + addWaypointsToMap(mapWaypoints, tracks, areas); // if there is an error, present to the user. if (!wasEntirelySuccessful) { diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/MapPanel.java b/Core/src/org/sleuthkit/autopsy/geolocation/MapPanel.java index 0304891afb..5f84a434e1 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/MapPanel.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/MapPanel.java @@ -23,6 +23,7 @@ import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; +import java.awt.Paint; import java.awt.Point; import java.awt.Rectangle; import java.awt.RenderingHints; @@ -30,6 +31,7 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; +import java.awt.geom.GeneralPath; import java.awt.geom.Point2D; import java.awt.image.BufferedImage; import java.beans.PropertyChangeEvent; @@ -91,11 +93,14 @@ final public class MapPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; private static final Set DOT_WAYPOINT_TYPES = new HashSet<>(); private static final int DOT_SIZE = 12; + private static final Set VERY_SMALL_DOT_WAYPOINT_TYPES = new HashSet<>(); + private static final int VERY_SMALL_DOT_SIZE = 6; private boolean zoomChanging; private KdTree waypointTree; private Set waypointSet; private List> tracks = new ArrayList<>(); + private List> areas = new ArrayList<>(); private Popup currentPopup; private final PopupFactory popupFactory; @@ -108,12 +113,13 @@ final public class MapPanel extends javax.swing.JPanel { private BufferedImage transparentWaypointImage; private MapWaypoint currentlySelectedWaypoint; - private Set currentlySelectedTrack; + private Set currentlySelectedSet; static { DOT_WAYPOINT_TYPES.add(ARTIFACT_TYPE.TSK_GPS_TRACKPOINT.getTypeID()); DOT_WAYPOINT_TYPES.add(ARTIFACT_TYPE.TSK_GPS_TRACK.getTypeID()); DOT_WAYPOINT_TYPES.add(ARTIFACT_TYPE.TSK_GPS_ROUTE.getTypeID()); + VERY_SMALL_DOT_WAYPOINT_TYPES.add(ARTIFACT_TYPE.TSK_GPS_AREA.getTypeID()); } /** @@ -241,6 +247,7 @@ final public class MapPanel extends javax.swing.JPanel { waypointPainter.setRenderer(new MapWaypointRenderer()); ArrayList> painters = new ArrayList<>(); + painters.add(new MapAreaRenderer(areas)); painters.add(new MapTrackRenderer(tracks)); painters.add(waypointPainter); @@ -342,6 +349,15 @@ final public class MapPanel extends javax.swing.JPanel { void setTracks(List> tracks) { this.tracks = tracks; } + + /** + * Stores the given list of areas from which to draw paths later + * + * @param areas + */ + void setAreas(List> areas) { + this.areas = areas; + } /** * Set the current zoom level. @@ -361,7 +377,7 @@ final public class MapPanel extends javax.swing.JPanel { void clearWaypoints() { waypointTree = null; currentlySelectedWaypoint = null; - currentlySelectedTrack = null; + currentlySelectedSet = null; if (currentPopup != null) { currentPopup.hide(); } @@ -514,6 +530,13 @@ final public class MapPanel extends javax.swing.JPanel { DOT_SIZE, DOT_SIZE ); + } else if (VERY_SMALL_DOT_WAYPOINT_TYPES.contains(nextWaypoint.getArtifactTypeID())) { + rect = new Rectangle( + pointX - (VERY_SMALL_DOT_SIZE / 2), + pointY - (VERY_SMALL_DOT_SIZE / 2), + VERY_SMALL_DOT_SIZE, + VERY_SMALL_DOT_SIZE + ); } else { rect = new Rectangle( pointX - (whiteWaypointImage.getWidth() / 2), @@ -717,16 +740,24 @@ final public class MapPanel extends javax.swing.JPanel { if (waypoints.size() > 0) { MapWaypoint selection = waypoints.get(0); currentlySelectedWaypoint = selection; - currentlySelectedTrack = null; + currentlySelectedSet = null; for (Set track : tracks) { if (track.contains(selection)) { - currentlySelectedTrack = track; + currentlySelectedSet = track; break; } } + if (currentlySelectedSet == null) { + for (Set area : areas) { + if (area.contains(selection)) { + currentlySelectedSet = area; + break; + } + } + } } else { currentlySelectedWaypoint = null; - currentlySelectedTrack = null; + currentlySelectedSet = null; } showDetailsPopup(); } @@ -755,6 +786,7 @@ final public class MapPanel extends javax.swing.JPanel { private class MapWaypointRenderer implements WaypointRenderer { private final Map dotImageCache = new HashMap<>(); + private final Map verySmallDotImageCache = new HashMap<>(); private final Map waypointImageCache = new HashMap<>(); /** @@ -766,7 +798,7 @@ final public class MapPanel extends javax.swing.JPanel { private Color getColor(MapWaypoint waypoint) { Color baseColor = waypoint.getColor(); if (waypoint.equals(currentlySelectedWaypoint) - || (currentlySelectedTrack != null && currentlySelectedTrack.contains(waypoint))) { + || (currentlySelectedSet != null && currentlySelectedSet.contains(waypoint))) { // Highlight this waypoint since it is selected return Color.YELLOW; } else { @@ -778,11 +810,11 @@ final public class MapPanel extends javax.swing.JPanel { * Creates a dot image with the specified color * * @param color the color of the new image + * @param s the size of the dot * * @return the new dot image */ - private BufferedImage createTrackDotImage(Color color) { - int s = DOT_SIZE; + private BufferedImage createTrackDotImage(Color color, int s) { BufferedImage ret = new BufferedImage(s, s, BufferedImage.TYPE_INT_ARGB); Graphics2D g = ret.createGraphics(); @@ -831,7 +863,13 @@ final public class MapPanel extends javax.swing.JPanel { if (DOT_WAYPOINT_TYPES.contains(waypoint.getArtifactTypeID())) { image = dotImageCache.computeIfAbsent(color, k -> { - return createTrackDotImage(color); + return createTrackDotImage(color, DOT_SIZE); + }); + // Center the dot on the GPS coordinate + y -= image.getHeight() / 2; + } else if (VERY_SMALL_DOT_WAYPOINT_TYPES.contains(waypoint.getArtifactTypeID())) { + image = verySmallDotImageCache.computeIfAbsent(color, k -> { + return createTrackDotImage(color, VERY_SMALL_DOT_SIZE); }); // Center the dot on the GPS coordinate y -= image.getHeight() / 2; @@ -867,6 +905,8 @@ final public class MapPanel extends javax.swing.JPanel { int lastY = 0; boolean first = true; + + GeneralPath polygon = new GeneralPath(GeneralPath.WIND_EVEN_ODD, track.size()); for (MapWaypoint wp : track) { Point2D p = map.getTileFactory().geoToPixel(wp.getPosition(), map.getZoom()); @@ -903,4 +943,66 @@ final public class MapPanel extends javax.swing.JPanel { g2d.dispose(); } } + + /** + * Renderer for map areas + */ + private class MapAreaRenderer implements Painter { + + private final List> areas; + + MapAreaRenderer(List> areas) { + this.areas = areas; + } + + private void drawArea(Set area, Graphics2D g, JXMapViewer map) { + if (area.isEmpty()) { + return; + } + boolean first = true; + + GeneralPath polygon = new GeneralPath(GeneralPath.WIND_EVEN_ODD, area.size()); + + for (MapWaypoint wp : area) { + Point2D p = map.getTileFactory().geoToPixel(wp.getPosition(), map.getZoom()); + int thisX = (int) p.getX(); + int thisY = (int) p.getY(); + + if (first) { + polygon.moveTo(thisX, thisY); + first = false; + } else { + polygon.lineTo(thisX, thisY); + } + } + polygon.closePath(); + + Color areaColor = area.iterator().next().getColor(); + g.setPaint(new Color((float)(areaColor.getRed() / 255.0), + (float)(areaColor.getGreen() / 255.0), + (float)(areaColor.getBlue() / 255.0), + .2f)); + g.fill(polygon); + g.draw(polygon); + } + + @Override + public void paint(Graphics2D g, JXMapViewer map, int w, int h) { + Graphics2D g2d = (Graphics2D) g.create(); + + Rectangle bounds = map.getViewportBounds(); + g2d.translate(-bounds.x, -bounds.y); + + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + g2d.setColor(Color.BLACK); + g2d.setStroke(new BasicStroke(2)); + + for (Set area : areas) { + drawArea(area, g2d, map); + } + + g2d.dispose(); + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/MapWaypoint.java b/Core/src/org/sleuthkit/autopsy/geolocation/MapWaypoint.java index 21799e19fa..8d51dd6a36 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/MapWaypoint.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/MapWaypoint.java @@ -79,6 +79,7 @@ final class MapWaypoint extends KdTree.XYZPoint implements org.jxmapviewer.viewe artifactTypesToColors.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACK.getTypeID(), Color.ORANGE); artifactTypesToColors.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT.getTypeID(), Color.ORANGE); artifactTypesToColors.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID(), Color.MAGENTA); + artifactTypesToColors.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_AREA.getTypeID(), new Color(0x8a2be2)); // Blue violet } private final Waypoint dataModelWaypoint; diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Area.java b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Area.java new file mode 100644 index 0000000000..021cc91e70 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Area.java @@ -0,0 +1,177 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2020 Basis Technology Corp. + * contact: carrier sleuthkit 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.geolocation.datamodel; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardAttribute; +import org.sleuthkit.datamodel.blackboardutils.attributes.BlackboardJsonAttrUtil; +import org.sleuthkit.datamodel.blackboardutils.attributes.BlackboardJsonAttrUtil.InvalidJsonException; +import org.sleuthkit.datamodel.blackboardutils.attributes.GeoAreaPoints; +import org.sleuthkit.autopsy.coreutils.Logger; + +/** + * A GPS track with which wraps the TSK_GPS_AREA artifact. + */ +public final class Area extends GeoPath { + private static final Logger LOGGER = Logger.getLogger(Track.class.getName()); + + /** + * Construct a new Area for the given artifact. + * + * @param artifact + * + * @throws GeoLocationDataException + */ + public Area(BlackboardArtifact artifact) throws GeoLocationDataException { + this(artifact, Waypoint.getAttributesFromArtifactAsMap(artifact)); + } + + /** + * Construct an Area for the given artifact and attributeMap. + * + * @param artifact TSK_GPD_TRACK artifact + * @param attributeMap Map of the artifact attributes + * + * @throws GeoLocationDataException + */ + private Area(BlackboardArtifact artifact, Map attributeMap) throws GeoLocationDataException { + super(artifact, getAreaName(attributeMap)); + + GeoAreaPoints points = getPointsList(attributeMap); + buildPath(points, artifact); + } + + /** + * Return the name of the area from the attributeMap. Track name is stored + * in the attribute TSK_NAME + * + * @param attributeMap + * + * @return Area name or empty string if none was available. + */ + private static String getAreaName(Map attributeMap) { + BlackboardAttribute attribute = attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME); + + return attribute != null ? attribute.getValueString() : ""; + } + + /** + * Create the list of AreaWaypoints from the GeoTrackPoint list. + * + * @param points GeoAreaPoints object. + * @param artifact The artifact to which these points belong + * + * @throws GeoLocationDataException + */ + @Messages({ + "# {0} - area name", + "GEOArea_point_label_header=Area outline point for area: {0}" + }) + private void buildPath(GeoAreaPoints points, BlackboardArtifact artifact) throws GeoLocationDataException { + for (GeoAreaPoints.AreaPoint point : points) { + addToPath(new AreaWaypoint(artifact, Bundle.GEOArea_point_label_header(getLabel()), point)); + } + } + + /** + * Returns the list of GeoAreaPoints from the attributeMap. Creates the + * GeoAreaPoint list from the TSK_GEO_AREAPOINTS attribute. + * + * @param attributeMap Map of artifact attributes. + * + * @return GeoTrackPoint list empty list if the attribute was not found. + * + * @throws GeoLocationDataException + */ + private GeoAreaPoints getPointsList(Map attributeMap) throws GeoLocationDataException { + BlackboardAttribute attribute = attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_AREAPOINTS); + if (attribute == null) { + LOGGER.log(Level.SEVERE, "No TSK_GEO_AREAPOINTS attribute was present on the artifact."); + throw new GeoLocationDataException("No TSK_GEO_AREAPOINTS attribute present in attribute map to parse."); + } + + try { + return BlackboardJsonAttrUtil.fromAttribute(attribute, GeoAreaPoints.class); + } catch (InvalidJsonException ex) { + LOGGER.log(Level.SEVERE, "TSK_GEO_AREAPOINTS could not be properly parsed from TSK_GEO_AREAPOINTS attribute."); + throw new GeoLocationDataException("Unable to parse area points in TSK_GEO_AREAPOINTS attribute", ex); + } + } + + /** + * A Waypoint subclass for the points of an area outline. + */ + final class AreaWaypoint extends Waypoint { + + private final List propertyList; + + /** + * Construct a AreaWaypoint. + * + * @param artifact the artifact to which this waypoint belongs + * + * @param pointLabel the label for the waypoint + * + * @param point GeoAreaPoint + * + * @throws GeoLocationDataException + */ + AreaWaypoint(BlackboardArtifact artifact, String pointLabel, GeoAreaPoints.AreaPoint point) throws GeoLocationDataException { + super(artifact, pointLabel, + null, + point.getLatitude(), + point.getLongitude(), + null, + null, + null, + Area.this); + + propertyList = createPropertyList(point); + } + + /** + * Overloaded to return a property list that is generated from the + * GeoTrackPoint instead of an artifact. + * + * @return unmodifiable list of Waypoint.Property + */ + @Override + public List getOtherProperties() { + return Collections.unmodifiableList(propertyList); + } + + /** + * Create a propertyList specific to GeoAreaPoints. + * + * @param point GeoAreaPoint to get values from. + * + * @return A list of Waypoint.properies. + */ + private List createPropertyList(GeoAreaPoints.AreaPoint point) { + List list = new ArrayList<>(); + return list; + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Bundle.properties-MERGED index d603e85b7b..bf54a777e9 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Bundle.properties-MERGED @@ -1,3 +1,5 @@ +# {0} - area name +GEOArea_point_label_header=Area outline point for area: {0} # {0} - track name GEOTrack_point_label_header=Trackpoint for track: {0} LastKnownWaypoint_Label=Last Known Location diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoPath.java b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoPath.java index a1d369808a..37d655d166 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoPath.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoPath.java @@ -62,13 +62,13 @@ public class GeoPath { } /** - * Gets the list of Routes from the TSK_GPS_TRACK artifacts. + * Gets the list of Tracks from the TSK_GPS_TRACK artifacts. * * @param skCase Currently open SleuthkitCase * @param sourceList List of source to return tracks from, maybe null to * return tracks from all sources * - * @return List of Route objects, empty list will be returned if no Routes + * @return List of Track objects, empty list will be returned if no tracks * were found * * @throws GeoLocationDataException @@ -94,6 +94,40 @@ public class GeoPath { } return new GeoLocationParseResult(tracks, allParsedSuccessfully); } + + /** + * Gets the list of Areas from the TSK_GPS_AREA artifacts. + * + * @param skCase Currently open SleuthkitCase + * @param sourceList List of source to return areas from, may be null to + * return areas from all sources + * + * @return List of Area objects, empty list will be returned if no areas + * were found + * + * @throws GeoLocationDataException + */ + public static GeoLocationParseResult getAreas(SleuthkitCase skCase, List sourceList) throws GeoLocationDataException { + List artifacts = null; + boolean allParsedSuccessfully = true; + List areas = new ArrayList<>(); + try { + artifacts = skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_AREA); + for (BlackboardArtifact artifact : artifacts) { + if (sourceList == null || sourceList.contains(artifact.getDataSource())) { + try { + areas.add(new Area(artifact)); + + } catch (GeoLocationDataException e) { + allParsedSuccessfully = false; + } + } + } + } catch (TskCoreException ex) { + throw new GeoLocationDataException("Unable to get artifacts for type: TSK_GPS_BOOKMARK", ex); + } + return new GeoLocationParseResult(areas, allParsedSuccessfully); + } /** * Path constructor. diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/WaypointBuilder.java b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/WaypointBuilder.java index 076ac8b8f9..917c1572cd 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/WaypointBuilder.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/WaypointBuilder.java @@ -178,6 +178,28 @@ public final class WaypointBuilder { return trackList; } + + /** + * Returns a list of areas from the given list of waypoints. + * + * @param waypoints A list of waypoints + * + * @return A list of areas or an empty list if none were found. + */ + public static List getAreas(List waypoints) { + List areaList = new ArrayList<>(); + for (Waypoint point : waypoints) { + GeoPath path = point.getParentGeoPath(); + if (path instanceof Area) { + Area area = (Area) path; + if (!areaList.contains(area)) { + areaList.add(area); + } + } + } + + return areaList; + } /** * Gets a list of Waypoints for TSK_GPS_TRACKPOINT artifacts. diff --git a/Core/src/org/sleuthkit/autopsy/images/gps-area.png b/Core/src/org/sleuthkit/autopsy/images/gps-area.png new file mode 100644 index 0000000000000000000000000000000000000000..32422261ad66ce9e4daec2b6426ee5210678d8f5 GIT binary patch literal 984 zcmV;}11J26P)EX>4Tx04R}tkv&MmKpe$iTcuJf9V{r~kfAzR5Eao)s#pXIrLEAagUO{|(4-+r zad8w}3l4rPRvlcNb#-tR1i=pwCr2km7b)?7NufoI2gm(*ckglc4)8WAOfkB~0Yx?S zR6HhRbE|^?6}=ch2(t)?%+M0)#SC1>*F8LZy^HcJ_j7-aJ~?kNz#|aPF-FVXW-reS>zUL%ahO;rcCggJtfVW%Q^XNjQ7PY> zby()S#aXG;SnHnrg~7bKlIA+iVZ^b71d$WEC0hc?#;FBimqAmGodJ6^M{fxdT2lU?pfi-jfDCoDd;=UD z0;5IBUUzwSPiJrco@w>>1FU3nzM^NH<^TWy24YJ`L;w~5769TvOoht;000SaNLh0L z01FcU01FcV0GgZ_00007bV*G`2jmME5jGZ^GeBSf000?uMObu0Z*6U5Zgc=ca%Ew3 zWn>_CX>@2HM@dakSAh-}00056NklEp7^a1zorn3NE^-{T{A#A#~HwRWV=}y0I8_<3cPlDOLWsKo8k>ZqL4Lx$#f!u%cAExh5%s&`EKc3i`wKH^l!P$(9w2# zou3#yLEb9R^KYV*VRZBxi;E$xR*x4i%cvkvbU3>*@Cv$nj$Y3}2%m)oC>FC!PUg9H z_a{;s8V$QV_>7i8DT7iFMe$!a3=L8m>~z8otjr!lbkW*nV`G@<>3w|PVQsC1l!oeD zdRjFBqtR~b{O)>&>W zdx-*(9aFmY7AXx<#wcZ&nc1gQ`EqhEjEs3)sdz|f&^qGs+&d1U!~P>}HtRK-$zG_s zA{T~Fu20?g?mypI`5g9P4`a-UQfr-CT6*27)wZ7fi~j+f`{8uE$SIWo0000 waypointList) { @@ -216,6 +219,11 @@ public final class KMLReport implements GeneralReportModule { result = ReportProgressPanel.ReportStatus.ERROR; errorMessage = Bundle.KMLReport_partialFailure(); } + entirelySuccessful = makeAreas(skCase); + if (!entirelySuccessful) { + result = ReportProgressPanel.ReportStatus.ERROR; + errorMessage = Bundle.KMLReport_partialFailure(); + } addLocationsToReport(skCase, baseReportDir); } catch (GeoLocationDataException | IOException | TskCoreException ex) { @@ -326,6 +334,11 @@ public final class KMLReport implements GeneralReportModule { CDATA cdataTrack = new CDATA("https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/gps-trackpoint.png"); //NON-NLS Element hrefTrack = new Element("href", ns).addContent(cdataTrack); //NON-NLS gpsTracksFolder.addContent(new Element("Icon", ns).addContent(hrefTrack)); //NON-NLS + + gpsAreasFolder = new Element("Folder", ns); //NON-NLS + CDATA cdataArea = new CDATA("https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/gps-area.png"); //NON-NLS + Element hrefArea = new Element("href", ns).addContent(cdataArea); //NON-NLS + gpsAreasFolder.addContent(new Element("Icon", ns).addContent(hrefArea)); //NON-NLS gpsExifMetadataFolder.addContent(new Element("name", ns).addContent("EXIF Metadata")); //NON-NLS gpsBookmarksFolder.addContent(new Element("name", ns).addContent("GPS Bookmarks")); //NON-NLS @@ -334,6 +347,7 @@ public final class KMLReport implements GeneralReportModule { gpsSearchesFolder.addContent(new Element("name", ns).addContent("GPS Searches")); //NON-NLS gpsTrackpointsFolder.addContent(new Element("name", ns).addContent("GPS Trackpoints")); //NON-NLS gpsTracksFolder.addContent(new Element("name", ns).addContent("GPS Tracks")); //NON-NLS + gpsAreasFolder.addContent(new Element("name", ns).addContent("GPS Areas")); //NON-NLS document.addContent(gpsExifMetadataFolder); document.addContent(gpsBookmarksFolder); @@ -342,6 +356,7 @@ public final class KMLReport implements GeneralReportModule { document.addContent(gpsSearchesFolder); document.addContent(gpsTrackpointsFolder); document.addContent(gpsTracksFolder); + document.addContent(gpsAreasFolder); return kmlDocument; } @@ -570,6 +585,62 @@ public final class KMLReport implements GeneralReportModule { point.getTimestamp(), element, formattedCoordinates(point.getLatitude(), point.getLongitude()))); //NON-NLS } } + + /** + * Add the area to the area folder in the document. + * + * @param skCase Currently open case. + * @return The operation was entirely successful. + * + * @throws TskCoreException + */ + boolean makeAreas(SleuthkitCase skCase) throws GeoLocationDataException, TskCoreException { + List areas; + boolean successful = true; + + if (waypointList == null) { + GeoLocationParseResult result = Area.getAreas(skCase, null); + areas = result.getItems(); + successful = result.isSuccessfullyParsed(); + } else { + areas = WaypointBuilder.getAreas(waypointList); + } + + for (Area area : areas) { + if(shouldFilterFromReport(area.getArtifact())) { + continue; + } + addAreaToReport(area); + } + + return successful; + } + + /** + * Add a area to the KML report. + * + * @param area + */ + private void addAreaToReport(Area area) { + List areaPoints = area.getPath(); + + if (areaPoints.isEmpty()) { + return; + } + + // Adding a folder with the area name so that all of the + // area border points will be grouped together. + Element areaFolder = new Element("Folder", ns); //NON-NLS + areaFolder.addContent(new Element("name", ns).addContent(area.getLabel())); //NON-NLS + gpsAreasFolder.addContent(areaFolder); + + // Create a polygon using the waypoints + Element element = makePolygon(areaPoints); + Waypoint firstWp = areaPoints.get(0); + areaFolder.addContent(makePlacemark("", + FeatureColor.GREEN, getFormattedDetails(firstWp, Bundle.Waypoint_Area_Point_Display_String()), + firstWp.getTimestamp(), element, formattedCoordinates(firstWp.getLatitude(), firstWp.getLongitude()))); //NON-NLS + } /** * Format a point time stamp (in seconds) to the report format. @@ -628,7 +699,7 @@ public final class KMLReport implements GeneralReportModule { point.addContent(coordinates); return point; - } + } /** * Create a LineString for use in a Placemark. Note in this method, start @@ -662,6 +733,35 @@ public final class KMLReport implements GeneralReportModule { return lineString; } + /** + * Create a Polygon for use in a Placemark. + * + * @param waypoints The waypoints making up the outline. + * + * @return the Polygon as an Element + */ + private Element makePolygon(List waypoints) { + + Element polygon = new Element("Polygon", ns); //NON-NLS + + Element altitudeMode = new Element("altitudeMode", ns).addContent("clampToGround"); //NON-NLS + polygon.addContent(altitudeMode); + + // KML uses lon, lat. Deliberately reversed.1 + Element coordinates = new Element("coordinates", ns); + for (Waypoint wp : waypoints) { + coordinates.addContent(wp.getLongitude() + "," + wp.getLatitude() + ",0 "); //NON-NLS + } + // Add the first one again + coordinates.addContent(waypoints.get(0).getLongitude() + "," + waypoints.get(0).getLatitude() + ",0 "); //NON-NLS + + Element linearRing = new Element("LinearRing", ns).addContent(coordinates); + Element outerBoundary = new Element("outerBoundaryIs", ns).addContent(linearRing); + polygon.addContent(outerBoundary); + + return polygon; + } + /** * Make a Placemark for use in displaying features. Takes a * coordinate-bearing feature (Point, LineString, etc) and places it in the From 821b733428c258b2600b4938a89bfad9cfa7293d Mon Sep 17 00:00:00 2001 From: apriestman Date: Tue, 24 Nov 2020 08:40:55 -0500 Subject: [PATCH 18/42] Cleanup --- .../autopsy/geolocation/AbstractWaypointFetcher.java | 9 ++++++--- .../sleuthkit/autopsy/ingest/Bundle.properties-MERGED | 2 -- .../sleuthkit/autopsy/report/modules/kml/KMLReport.java | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/AbstractWaypointFetcher.java b/Core/src/org/sleuthkit/autopsy/geolocation/AbstractWaypointFetcher.java index 955eb3dba7..613ffc3c85 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/AbstractWaypointFetcher.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/AbstractWaypointFetcher.java @@ -118,12 +118,12 @@ abstract class AbstractWaypointFetcher implements WaypointBuilder.WaypointFilter for (List t : geoDataSet.getAreas()) { areaSets.add(MapWaypoint.getWaypoints(t)); } - // TODO check for area errors too TODO TODO + handleFilteredWaypointSet( pointSet, trackSets, areaSets, (trackResults == null || trackResults.isSuccessfullyParsed()) - && (areaResults == null || areaResults.isSuccessfullyParsed()) - && waypointResults.isSuccessfullyParsed()); + && (areaResults == null || areaResults.isSuccessfullyParsed()) + && waypointResults.isSuccessfullyParsed()); } /** @@ -296,6 +296,9 @@ abstract class AbstractWaypointFetcher implements WaypointBuilder.WaypointFilter return -1L; } + /** + * Utility class to collect filtered GPS objects. + */ static class GeoDataSet { private final List waypoints; private final List> tracks; diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties-MERGED index c2ce001e71..157506a57f 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties-MERGED @@ -1,6 +1,4 @@ CTL_RunIngestAction=Run Ingest -CustomGPSIngestModule_Description=Just makes a few custom artifacts with GPS data -CustomGPSIngestModule_Name=Custom GPS Module IngestJobSettingsPanel.IngestModulesTableRenderer.info.message=A previous version of this ingest module has been run before on this data source. IngestJobSettingsPanel.IngestModulesTableRenderer.warning.message=This ingest module has been run before on this data source. IngestJobSettingsPanel.noPerRunSettings=The selected module has no per-run settings. diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/kml/KMLReport.java b/Core/src/org/sleuthkit/autopsy/report/modules/kml/KMLReport.java index 2cb311e6b9..7ca8749e15 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/kml/KMLReport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/kml/KMLReport.java @@ -747,7 +747,7 @@ public final class KMLReport implements GeneralReportModule { Element altitudeMode = new Element("altitudeMode", ns).addContent("clampToGround"); //NON-NLS polygon.addContent(altitudeMode); - // KML uses lon, lat. Deliberately reversed.1 + // KML uses lon, lat. Deliberately reversed. Element coordinates = new Element("coordinates", ns); for (Waypoint wp : waypoints) { coordinates.addContent(wp.getLongitude() + "," + wp.getLatitude() + ",0 "); //NON-NLS From a843d34b2c883fc27e9c5b0b6fc87710b2c5d313 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 24 Nov 2020 12:37:10 -0500 Subject: [PATCH 19/42] domain categorization --- .../autopsy/coreutils/DomainCategorizer.java | 206 + .../autopsy/coreutils/NetworkUtils.java | 75 +- .../autopsy/coreutils/public_suffix_list.dat | 13494 ++++++++++++++++ 3 files changed, 13715 insertions(+), 60 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/coreutils/DomainCategorizer.java create mode 100644 Core/src/org/sleuthkit/autopsy/coreutils/public_suffix_list.dat diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/DomainCategorizer.java b/Core/src/org/sleuthkit/autopsy/coreutils/DomainCategorizer.java new file mode 100644 index 0000000000..63b1a07b47 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/coreutils/DomainCategorizer.java @@ -0,0 +1,206 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit 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.coreutils; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.HashMap; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.apache.commons.lang3.StringUtils; + +/** + * Attempts to get the domain from a url/domain provided removing the + * subdomain(s). + */ +class DomainCategorizer { + + /** + * This is a node in the trie. Children in the hashmap are identified by + * token. So for example, for a domain google.co.uk, the top level category + * would have an entry for "uk" linking to a domain category with "co". + */ + private static class DomainCategory extends HashMap { + + private DomainCategory getOrAddChild(String childKey) { + DomainCategory cat = this.get(childKey); + if (cat == null) { + cat = new DomainCategory(); + this.put(childKey, cat); + } + + return cat; + } + } + + // Character for joining domain segments. + private static final String JOINER = "."; + // delimiter when used with regex + private static final String DELIMITER = "\\" + JOINER; + + // taken from https://publicsuffix.org/list/public_suffix_list.dat + // file containing line seperated suffixes + private static final String DOMAIN_LIST = "public_suffix_list.dat"; + + // token for comments + private static final String COMMENT_TOKEN = "//"; + + // singleton instance of this class. + private static DomainCategorizer categorizer = null; + + /** + * Returns the singleton instance of this class. + * + * @return The DomainCategorizer instance. + * @throws IOException + */ + static DomainCategorizer getInstance() throws IOException { + if (categorizer == null) { + categorizer = load(); + } + + return categorizer; + } + + /** + * Loads a DomainCategorizer instance using the public suffix list. + * + * @return The DomainCategorizer instance. + * @throws IOException If there is an error reading the file. + */ + private static DomainCategorizer load() throws IOException { + InputStream is = DomainCategorizer.class.getResourceAsStream(DOMAIN_LIST); + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + DomainCategorizer categorizer = new DomainCategorizer(); + while (reader.ready()) { + String line = reader.readLine(); + String trimmed = line.trim(); + if (!StringUtils.isBlank(trimmed) && !trimmed.startsWith(COMMENT_TOKEN)) { + categorizer.addDomainSuffix(trimmed); + } + } + + return categorizer; + } + + private DomainCategorizer() { + } + + // The top-level trie node. + private final DomainCategory trie = new DomainCategory(); + + /** + * Parses a domain suffix and adds components to the trie in reverse order + * (i.e. ".co.uk" becomes "uk" -> "co"). + * + * @param domainSuffix The domain suffix. + */ + private void addDomainSuffix(String domainSuffix) { + if (StringUtils.isBlank(domainSuffix)) { + return; + } + + String[] tokens = domainSuffix.split(DELIMITER); + + DomainCategory cat = trie; + for (int i = tokens.length - 1; i >= 0; i--) { + String token = tokens[i]; + if (StringUtils.isBlank(token)) { + continue; + } + + cat = cat.getOrAddChild(tokens[i]); + } + } + + // based on syntax shown here: https://en.wikipedia.org/wiki/URL + // and intially based on regex provided here: https://stackoverflow.com/a/9608008 + Pattern pattern = Pattern.compile("^\\s*(?:[^:\\/?#]+:)?(?:\\/\\/)?(?:[^\\/?#@]*@)?([^:\\/?#]*)"); + + /** + * Sanitizes a url string so that just the host is extracted ignoring + * scheme, userinfo, port, and path if present. + * + * @param url The url-like string. + * @return The host removing port, user info, scheme, and path + */ + private String sanitizedHost(String url) { + if (StringUtils.isBlank(url)) { + return null; + } + + Matcher m = pattern.matcher(url); + if (m.find()) { + return m.group(1); + } else { + return null; + } + } + + /** + * Gets the domain by attempting to identify the host without the subdomain. + * If no host can be determined, the full parameter is returned. If no + * domain can be determined, the host is returned. + * + * @param url The url/domain to query for. + * @return If provided argument is blank, null is returned. If no host can + * be determined the 'domain' parameter is returned. If no domain suffixes + * can be identified, the full host is returned. If a host and suffixes are + * identified, the domain (all suffixes with a prefix of the next token) are + * returned. + */ + String getDomain(String url) { + if (StringUtils.isBlank(url)) { + return null; + } + + String host = sanitizedHost(url); + if (host == null) { + return url; + } + + List tokens = Stream.of(host.split(DELIMITER)) + .filter(StringUtils::isNotBlank) + .collect(Collectors.toList()); + + int idx = tokens.size() - 1; + DomainCategory cat = trie; + + for (; idx >= 0; idx--) { + cat = cat.get(tokens.get(idx)); + if (cat == null) { + break; + } + } + + // if first suffix cannot be found, return the whole domain + if (idx == tokens.size() - 1) { + return host; + } else { + int minIndex = Math.max(0, idx); + List subList = tokens.subList(minIndex, tokens.size()); + return String.join(JOINER, subList); + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/NetworkUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/NetworkUtils.java index 42266745f2..2b9249d278 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/NetworkUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/NetworkUtils.java @@ -18,13 +18,16 @@ */ package org.sleuthkit.autopsy.coreutils; +import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.net.UnknownHostException; -import java.util.StringTokenizer; +import java.util.logging.Level; public class NetworkUtils { - + + private static final Logger logger = Logger.getLogger(NetworkUtils.class.getName()); + private NetworkUtils() { } @@ -32,7 +35,7 @@ public class NetworkUtils { * Set the host name variable. Sometimes the network can be finicky, so the * answer returned by getHostName() could throw an exception or be null. * Have it read the environment variable if getHostName() is unsuccessful. - * + * * @return the local host name */ public static String getLocalHostName() { @@ -49,63 +52,11 @@ public class NetworkUtils { } return hostName; } - - /** - * Attempt to manually extract the domain from a URL. - * - * @param url - * @return empty string if no domain could be found - */ - private static String getBaseDomain(String url) { - String host = null; - - //strip protocol - String cleanUrl = url.replaceFirst(".*:\\/\\/", ""); - - //strip after slashes - String dirToks[] = cleanUrl.split("\\/"); - if (dirToks.length > 0) { - host = dirToks[0]; - } else { - host = cleanUrl; - } - - //get the domain part from host (last 2) - StringTokenizer tok = new StringTokenizer(host, "."); - StringBuilder hostB = new StringBuilder(); - int toks = tok.countTokens(); - - for (int count = 0; count < toks; ++count) { - String part = tok.nextToken(); - int diff = toks - count; - if (diff < 3) { - hostB.append(part); - } - if (diff == 2) { - hostB.append("."); - } - } - - - String base = hostB.toString(); - // verify there are no special characters in there - if (base.matches(".*[~`!@#$%^&\\*\\(\\)\\+={}\\[\\];:\\?<>,/ ].*")) { - return ""; - } - - //verify that the base domain actually has a '.', details JIRA-4609 - if(!base.contains(".")) { - return ""; - } - - return base; - } /** - * Attempt to extract the domain from a URL. - * Will start by using the built-in URL class, and if that fails will - * try to extract it manually. - * + * Attempt to extract the domain from a URL. Will start by using the + * built-in URL class, and if that fails will try to extract it manually. + * * @param urlString The URL to extract the domain from * @return empty string if no domain name was found */ @@ -124,9 +75,13 @@ public class NetworkUtils { //was not a valid URL, try a less picky method if (result == null || result.trim().isEmpty()) { - return getBaseDomain(urlString); + try { + return DomainCategorizer.getInstance().getDomain(urlString); + } catch (IOException ex) { + logger.log(Level.SEVERE, "Unable to load resources for domain categorization.", ex); + } } return result; } - + } diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/public_suffix_list.dat b/Core/src/org/sleuthkit/autopsy/coreutils/public_suffix_list.dat new file mode 100644 index 0000000000..6c36c21dbe --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/coreutils/public_suffix_list.dat @@ -0,0 +1,13494 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +// Please pull this list from, and only from https://publicsuffix.org/list/public_suffix_list.dat, +// rather than any other VCS sites. Pulling from any other URL is not guaranteed to be supported. + +// Instructions on pulling and using this list can be found at https://publicsuffix.org/list/. + +// ===BEGIN ICANN DOMAINS=== + +// ac : https://en.wikipedia.org/wiki/.ac +ac +com.ac +edu.ac +gov.ac +net.ac +mil.ac +org.ac + +// ad : https://en.wikipedia.org/wiki/.ad +ad +nom.ad + +// ae : https://en.wikipedia.org/wiki/.ae +// see also: "Domain Name Eligibility Policy" at http://www.aeda.ae/eng/aepolicy.php +ae +co.ae +net.ae +org.ae +sch.ae +ac.ae +gov.ae +mil.ae + +// aero : see https://www.information.aero/index.php?id=66 +aero +accident-investigation.aero +accident-prevention.aero +aerobatic.aero +aeroclub.aero +aerodrome.aero +agents.aero +aircraft.aero +airline.aero +airport.aero +air-surveillance.aero +airtraffic.aero +air-traffic-control.aero +ambulance.aero +amusement.aero +association.aero +author.aero +ballooning.aero +broker.aero +caa.aero +cargo.aero +catering.aero +certification.aero +championship.aero +charter.aero +civilaviation.aero +club.aero +conference.aero +consultant.aero +consulting.aero +control.aero +council.aero +crew.aero +design.aero +dgca.aero +educator.aero +emergency.aero +engine.aero +engineer.aero +entertainment.aero +equipment.aero +exchange.aero +express.aero +federation.aero +flight.aero +fuel.aero +gliding.aero +government.aero +groundhandling.aero +group.aero +hanggliding.aero +homebuilt.aero +insurance.aero +journal.aero +journalist.aero +leasing.aero +logistics.aero +magazine.aero +maintenance.aero +media.aero +microlight.aero +modelling.aero +navigation.aero +parachuting.aero +paragliding.aero +passenger-association.aero +pilot.aero +press.aero +production.aero +recreation.aero +repbody.aero +res.aero +research.aero +rotorcraft.aero +safety.aero +scientist.aero +services.aero +show.aero +skydiving.aero +software.aero +student.aero +trader.aero +trading.aero +trainer.aero +union.aero +workinggroup.aero +works.aero + +// af : http://www.nic.af/help.jsp +af +gov.af +com.af +org.af +net.af +edu.af + +// ag : http://www.nic.ag/prices.htm +ag +com.ag +org.ag +net.ag +co.ag +nom.ag + +// ai : http://nic.com.ai/ +ai +off.ai +com.ai +net.ai +org.ai + +// al : http://www.ert.gov.al/ert_alb/faq_det.html?Id=31 +al +com.al +edu.al +gov.al +mil.al +net.al +org.al + +// am : https://www.amnic.net/policy/en/Policy_EN.pdf +am +co.am +com.am +commune.am +net.am +org.am + +// ao : https://en.wikipedia.org/wiki/.ao +// http://www.dns.ao/REGISTR.DOC +ao +ed.ao +gv.ao +og.ao +co.ao +pb.ao +it.ao + +// aq : https://en.wikipedia.org/wiki/.aq +aq + +// ar : https://nic.ar/nic-argentina/normativa-vigente +ar +com.ar +edu.ar +gob.ar +gov.ar +int.ar +mil.ar +musica.ar +net.ar +org.ar +tur.ar + +// arpa : https://en.wikipedia.org/wiki/.arpa +// Confirmed by registry 2008-06-18 +arpa +e164.arpa +in-addr.arpa +ip6.arpa +iris.arpa +uri.arpa +urn.arpa + +// as : https://en.wikipedia.org/wiki/.as +as +gov.as + +// asia : https://en.wikipedia.org/wiki/.asia +asia + +// at : https://en.wikipedia.org/wiki/.at +// Confirmed by registry 2008-06-17 +at +ac.at +co.at +gv.at +or.at +sth.ac.at + +// au : https://en.wikipedia.org/wiki/.au +// http://www.auda.org.au/ +au +// 2LDs +com.au +net.au +org.au +edu.au +gov.au +asn.au +id.au +// Historic 2LDs (closed to new registration, but sites still exist) +info.au +conf.au +oz.au +// CGDNs - http://www.cgdn.org.au/ +act.au +nsw.au +nt.au +qld.au +sa.au +tas.au +vic.au +wa.au +// 3LDs +act.edu.au +catholic.edu.au +// eq.edu.au - Removed at the request of the Queensland Department of Education +nsw.edu.au +nt.edu.au +qld.edu.au +sa.edu.au +tas.edu.au +vic.edu.au +wa.edu.au +// act.gov.au Bug 984824 - Removed at request of Greg Tankard +// nsw.gov.au Bug 547985 - Removed at request of +// nt.gov.au Bug 940478 - Removed at request of Greg Connors +qld.gov.au +sa.gov.au +tas.gov.au +vic.gov.au +wa.gov.au +// 4LDs +// education.tas.edu.au - Removed at the request of the Department of Education Tasmania +schools.nsw.edu.au + +// aw : https://en.wikipedia.org/wiki/.aw +aw +com.aw + +// ax : https://en.wikipedia.org/wiki/.ax +ax + +// az : https://en.wikipedia.org/wiki/.az +az +com.az +net.az +int.az +gov.az +org.az +edu.az +info.az +pp.az +mil.az +name.az +pro.az +biz.az + +// ba : http://nic.ba/users_data/files/pravilnik_o_registraciji.pdf +ba +com.ba +edu.ba +gov.ba +mil.ba +net.ba +org.ba + +// bb : https://en.wikipedia.org/wiki/.bb +bb +biz.bb +co.bb +com.bb +edu.bb +gov.bb +info.bb +net.bb +org.bb +store.bb +tv.bb + +// bd : https://en.wikipedia.org/wiki/.bd +*.bd + +// be : https://en.wikipedia.org/wiki/.be +// Confirmed by registry 2008-06-08 +be +ac.be + +// bf : https://en.wikipedia.org/wiki/.bf +bf +gov.bf + +// bg : https://en.wikipedia.org/wiki/.bg +// https://www.register.bg/user/static/rules/en/index.html +bg +a.bg +b.bg +c.bg +d.bg +e.bg +f.bg +g.bg +h.bg +i.bg +j.bg +k.bg +l.bg +m.bg +n.bg +o.bg +p.bg +q.bg +r.bg +s.bg +t.bg +u.bg +v.bg +w.bg +x.bg +y.bg +z.bg +0.bg +1.bg +2.bg +3.bg +4.bg +5.bg +6.bg +7.bg +8.bg +9.bg + +// bh : https://en.wikipedia.org/wiki/.bh +bh +com.bh +edu.bh +net.bh +org.bh +gov.bh + +// bi : https://en.wikipedia.org/wiki/.bi +// http://whois.nic.bi/ +bi +co.bi +com.bi +edu.bi +or.bi +org.bi + +// biz : https://en.wikipedia.org/wiki/.biz +biz + +// bj : https://en.wikipedia.org/wiki/.bj +bj +asso.bj +barreau.bj +gouv.bj + +// bm : http://www.bermudanic.bm/dnr-text.txt +bm +com.bm +edu.bm +gov.bm +net.bm +org.bm + +// bn : http://www.bnnic.bn/faqs +bn +com.bn +edu.bn +gov.bn +net.bn +org.bn + +// bo : https://nic.bo/delegacion2015.php#h-1.10 +bo +com.bo +edu.bo +gob.bo +int.bo +org.bo +net.bo +mil.bo +tv.bo +web.bo +// Social Domains +academia.bo +agro.bo +arte.bo +blog.bo +bolivia.bo +ciencia.bo +cooperativa.bo +democracia.bo +deporte.bo +ecologia.bo +economia.bo +empresa.bo +indigena.bo +industria.bo +info.bo +medicina.bo +movimiento.bo +musica.bo +natural.bo +nombre.bo +noticias.bo +patria.bo +politica.bo +profesional.bo +plurinacional.bo +pueblo.bo +revista.bo +salud.bo +tecnologia.bo +tksat.bo +transporte.bo +wiki.bo + +// br : http://registro.br/dominio/categoria.html +// Submitted by registry +br +9guacu.br +abc.br +adm.br +adv.br +agr.br +aju.br +am.br +anani.br +aparecida.br +app.br +arq.br +art.br +ato.br +b.br +barueri.br +belem.br +bhz.br +bib.br +bio.br +blog.br +bmd.br +boavista.br +bsb.br +campinagrande.br +campinas.br +caxias.br +cim.br +cng.br +cnt.br +com.br +contagem.br +coop.br +coz.br +cri.br +cuiaba.br +curitiba.br +def.br +des.br +det.br +dev.br +ecn.br +eco.br +edu.br +emp.br +enf.br +eng.br +esp.br +etc.br +eti.br +far.br +feira.br +flog.br +floripa.br +fm.br +fnd.br +fortal.br +fot.br +foz.br +fst.br +g12.br +geo.br +ggf.br +goiania.br +gov.br +// gov.br 26 states + df https://en.wikipedia.org/wiki/States_of_Brazil +ac.gov.br +al.gov.br +am.gov.br +ap.gov.br +ba.gov.br +ce.gov.br +df.gov.br +es.gov.br +go.gov.br +ma.gov.br +mg.gov.br +ms.gov.br +mt.gov.br +pa.gov.br +pb.gov.br +pe.gov.br +pi.gov.br +pr.gov.br +rj.gov.br +rn.gov.br +ro.gov.br +rr.gov.br +rs.gov.br +sc.gov.br +se.gov.br +sp.gov.br +to.gov.br +gru.br +imb.br +ind.br +inf.br +jab.br +jampa.br +jdf.br +joinville.br +jor.br +jus.br +leg.br +lel.br +log.br +londrina.br +macapa.br +maceio.br +manaus.br +maringa.br +mat.br +med.br +mil.br +morena.br +mp.br +mus.br +natal.br +net.br +niteroi.br +*.nom.br +not.br +ntr.br +odo.br +ong.br +org.br +osasco.br +palmas.br +poa.br +ppg.br +pro.br +psc.br +psi.br +pvh.br +qsl.br +radio.br +rec.br +recife.br +rep.br +ribeirao.br +rio.br +riobranco.br +riopreto.br +salvador.br +sampa.br +santamaria.br +santoandre.br +saobernardo.br +saogonca.br +seg.br +sjc.br +slg.br +slz.br +sorocaba.br +srv.br +taxi.br +tc.br +tec.br +teo.br +the.br +tmp.br +trd.br +tur.br +tv.br +udi.br +vet.br +vix.br +vlog.br +wiki.br +zlg.br + +// bs : http://www.nic.bs/rules.html +bs +com.bs +net.bs +org.bs +edu.bs +gov.bs + +// bt : https://en.wikipedia.org/wiki/.bt +bt +com.bt +edu.bt +gov.bt +net.bt +org.bt + +// bv : No registrations at this time. +// Submitted by registry +bv + +// bw : https://en.wikipedia.org/wiki/.bw +// http://www.gobin.info/domainname/bw.doc +// list of other 2nd level tlds ? +bw +co.bw +org.bw + +// by : https://en.wikipedia.org/wiki/.by +// http://tld.by/rules_2006_en.html +// list of other 2nd level tlds ? +by +gov.by +mil.by +// Official information does not indicate that com.by is a reserved +// second-level domain, but it's being used as one (see www.google.com.by and +// www.yahoo.com.by, for example), so we list it here for safety's sake. +com.by + +// http://hoster.by/ +of.by + +// bz : https://en.wikipedia.org/wiki/.bz +// http://www.belizenic.bz/ +bz +com.bz +net.bz +org.bz +edu.bz +gov.bz + +// ca : https://en.wikipedia.org/wiki/.ca +ca +// ca geographical names +ab.ca +bc.ca +mb.ca +nb.ca +nf.ca +nl.ca +ns.ca +nt.ca +nu.ca +on.ca +pe.ca +qc.ca +sk.ca +yk.ca +// gc.ca: https://en.wikipedia.org/wiki/.gc.ca +// see also: http://registry.gc.ca/en/SubdomainFAQ +gc.ca + +// cat : https://en.wikipedia.org/wiki/.cat +cat + +// cc : https://en.wikipedia.org/wiki/.cc +cc + +// cd : https://en.wikipedia.org/wiki/.cd +// see also: https://www.nic.cd/domain/insertDomain_2.jsp?act=1 +cd +gov.cd + +// cf : https://en.wikipedia.org/wiki/.cf +cf + +// cg : https://en.wikipedia.org/wiki/.cg +cg + +// ch : https://en.wikipedia.org/wiki/.ch +ch + +// ci : https://en.wikipedia.org/wiki/.ci +// http://www.nic.ci/index.php?page=charte +ci +org.ci +or.ci +com.ci +co.ci +edu.ci +ed.ci +ac.ci +net.ci +go.ci +asso.ci +aéroport.ci +int.ci +presse.ci +md.ci +gouv.ci + +// ck : https://en.wikipedia.org/wiki/.ck +*.ck +!www.ck + +// cl : https://www.nic.cl +// Confirmed by .CL registry +cl +aprendemas.cl +co.cl +gob.cl +gov.cl +mil.cl + +// cm : https://en.wikipedia.org/wiki/.cm plus bug 981927 +cm +co.cm +com.cm +gov.cm +net.cm + +// cn : https://en.wikipedia.org/wiki/.cn +// Submitted by registry +cn +ac.cn +com.cn +edu.cn +gov.cn +net.cn +org.cn +mil.cn +公司.cn +网络.cn +網絡.cn +// cn geographic names +ah.cn +bj.cn +cq.cn +fj.cn +gd.cn +gs.cn +gz.cn +gx.cn +ha.cn +hb.cn +he.cn +hi.cn +hl.cn +hn.cn +jl.cn +js.cn +jx.cn +ln.cn +nm.cn +nx.cn +qh.cn +sc.cn +sd.cn +sh.cn +sn.cn +sx.cn +tj.cn +xj.cn +xz.cn +yn.cn +zj.cn +hk.cn +mo.cn +tw.cn + +// co : https://en.wikipedia.org/wiki/.co +// Submitted by registry +co +arts.co +com.co +edu.co +firm.co +gov.co +info.co +int.co +mil.co +net.co +nom.co +org.co +rec.co +web.co + +// com : https://en.wikipedia.org/wiki/.com +com + +// coop : https://en.wikipedia.org/wiki/.coop +coop + +// cr : http://www.nic.cr/niccr_publico/showRegistroDominiosScreen.do +cr +ac.cr +co.cr +ed.cr +fi.cr +go.cr +or.cr +sa.cr + +// cu : https://en.wikipedia.org/wiki/.cu +cu +com.cu +edu.cu +org.cu +net.cu +gov.cu +inf.cu + +// cv : https://en.wikipedia.org/wiki/.cv +cv + +// cw : http://www.una.cw/cw_registry/ +// Confirmed by registry 2013-03-26 +cw +com.cw +edu.cw +net.cw +org.cw + +// cx : https://en.wikipedia.org/wiki/.cx +// list of other 2nd level tlds ? +cx +gov.cx + +// cy : http://www.nic.cy/ +// Submitted by registry Panayiotou Fotia +cy +ac.cy +biz.cy +com.cy +ekloges.cy +gov.cy +ltd.cy +name.cy +net.cy +org.cy +parliament.cy +press.cy +pro.cy +tm.cy + +// cz : https://en.wikipedia.org/wiki/.cz +cz + +// de : https://en.wikipedia.org/wiki/.de +// Confirmed by registry (with technical +// reservations) 2008-07-01 +de + +// dj : https://en.wikipedia.org/wiki/.dj +dj + +// dk : https://en.wikipedia.org/wiki/.dk +// Confirmed by registry 2008-06-17 +dk + +// dm : https://en.wikipedia.org/wiki/.dm +dm +com.dm +net.dm +org.dm +edu.dm +gov.dm + +// do : https://en.wikipedia.org/wiki/.do +do +art.do +com.do +edu.do +gob.do +gov.do +mil.do +net.do +org.do +sld.do +web.do + +// dz : http://www.nic.dz/images/pdf_nic/charte.pdf +dz +art.dz +asso.dz +com.dz +edu.dz +gov.dz +org.dz +net.dz +pol.dz +soc.dz +tm.dz + +// ec : http://www.nic.ec/reg/paso1.asp +// Submitted by registry +ec +com.ec +info.ec +net.ec +fin.ec +k12.ec +med.ec +pro.ec +org.ec +edu.ec +gov.ec +gob.ec +mil.ec + +// edu : https://en.wikipedia.org/wiki/.edu +edu + +// ee : http://www.eenet.ee/EENet/dom_reeglid.html#lisa_B +ee +edu.ee +gov.ee +riik.ee +lib.ee +med.ee +com.ee +pri.ee +aip.ee +org.ee +fie.ee + +// eg : https://en.wikipedia.org/wiki/.eg +eg +com.eg +edu.eg +eun.eg +gov.eg +mil.eg +name.eg +net.eg +org.eg +sci.eg + +// er : https://en.wikipedia.org/wiki/.er +*.er + +// es : https://www.nic.es/site_ingles/ingles/dominios/index.html +es +com.es +nom.es +org.es +gob.es +edu.es + +// et : https://en.wikipedia.org/wiki/.et +et +com.et +gov.et +org.et +edu.et +biz.et +name.et +info.et +net.et + +// eu : https://en.wikipedia.org/wiki/.eu +eu + +// fi : https://en.wikipedia.org/wiki/.fi +fi +// aland.fi : https://en.wikipedia.org/wiki/.ax +// This domain is being phased out in favor of .ax. As there are still many +// domains under aland.fi, we still keep it on the list until aland.fi is +// completely removed. +// TODO: Check for updates (expected to be phased out around Q1/2009) +aland.fi + +// fj : http://domains.fj/ +// Submitted by registry 2020-02-11 +fj +ac.fj +biz.fj +com.fj +gov.fj +info.fj +mil.fj +name.fj +net.fj +org.fj +pro.fj + +// fk : https://en.wikipedia.org/wiki/.fk +*.fk + +// fm : https://en.wikipedia.org/wiki/.fm +com.fm +edu.fm +net.fm +org.fm +fm + +// fo : https://en.wikipedia.org/wiki/.fo +fo + +// fr : http://www.afnic.fr/ +// domaines descriptifs : https://www.afnic.fr/medias/documents/Cadre_legal/Afnic_Naming_Policy_12122016_VEN.pdf +fr +asso.fr +com.fr +gouv.fr +nom.fr +prd.fr +tm.fr +// domaines sectoriels : https://www.afnic.fr/en/products-and-services/the-fr-tld/sector-based-fr-domains-4.html +aeroport.fr +avocat.fr +avoues.fr +cci.fr +chambagri.fr +chirurgiens-dentistes.fr +experts-comptables.fr +geometre-expert.fr +greta.fr +huissier-justice.fr +medecin.fr +notaires.fr +pharmacien.fr +port.fr +veterinaire.fr + +// ga : https://en.wikipedia.org/wiki/.ga +ga + +// gb : This registry is effectively dormant +// Submitted by registry +gb + +// gd : https://en.wikipedia.org/wiki/.gd +edu.gd +gov.gd +gd + +// ge : http://www.nic.net.ge/policy_en.pdf +ge +com.ge +edu.ge +gov.ge +org.ge +mil.ge +net.ge +pvt.ge + +// gf : https://en.wikipedia.org/wiki/.gf +gf + +// gg : http://www.channelisles.net/register-domains/ +// Confirmed by registry 2013-11-28 +gg +co.gg +net.gg +org.gg + +// gh : https://en.wikipedia.org/wiki/.gh +// see also: http://www.nic.gh/reg_now.php +// Although domains directly at second level are not possible at the moment, +// they have been possible for some time and may come back. +gh +com.gh +edu.gh +gov.gh +org.gh +mil.gh + +// gi : http://www.nic.gi/rules.html +gi +com.gi +ltd.gi +gov.gi +mod.gi +edu.gi +org.gi + +// gl : https://en.wikipedia.org/wiki/.gl +// http://nic.gl +gl +co.gl +com.gl +edu.gl +net.gl +org.gl + +// gm : http://www.nic.gm/htmlpages%5Cgm-policy.htm +gm + +// gn : http://psg.com/dns/gn/gn.txt +// Submitted by registry +gn +ac.gn +com.gn +edu.gn +gov.gn +org.gn +net.gn + +// gov : https://en.wikipedia.org/wiki/.gov +gov + +// gp : http://www.nic.gp/index.php?lang=en +gp +com.gp +net.gp +mobi.gp +edu.gp +org.gp +asso.gp + +// gq : https://en.wikipedia.org/wiki/.gq +gq + +// gr : https://grweb.ics.forth.gr/english/1617-B-2005.html +// Submitted by registry +gr +com.gr +edu.gr +net.gr +org.gr +gov.gr + +// gs : https://en.wikipedia.org/wiki/.gs +gs + +// gt : https://www.gt/sitio/registration_policy.php?lang=en +gt +com.gt +edu.gt +gob.gt +ind.gt +mil.gt +net.gt +org.gt + +// gu : http://gadao.gov.gu/register.html +// University of Guam : https://www.uog.edu +// Submitted by uognoc@triton.uog.edu +gu +com.gu +edu.gu +gov.gu +guam.gu +info.gu +net.gu +org.gu +web.gu + +// gw : https://en.wikipedia.org/wiki/.gw +gw + +// gy : https://en.wikipedia.org/wiki/.gy +// http://registry.gy/ +gy +co.gy +com.gy +edu.gy +gov.gy +net.gy +org.gy + +// hk : https://www.hkirc.hk +// Submitted by registry +hk +com.hk +edu.hk +gov.hk +idv.hk +net.hk +org.hk +公司.hk +教育.hk +敎育.hk +政府.hk +個人.hk +个人.hk +箇人.hk +網络.hk +网络.hk +组織.hk +網絡.hk +网絡.hk +组织.hk +組織.hk +組织.hk + +// hm : https://en.wikipedia.org/wiki/.hm +hm + +// hn : http://www.nic.hn/politicas/ps02,,05.html +hn +com.hn +edu.hn +org.hn +net.hn +mil.hn +gob.hn + +// hr : http://www.dns.hr/documents/pdf/HRTLD-regulations.pdf +hr +iz.hr +from.hr +name.hr +com.hr + +// ht : http://www.nic.ht/info/charte.cfm +ht +com.ht +shop.ht +firm.ht +info.ht +adult.ht +net.ht +pro.ht +org.ht +med.ht +art.ht +coop.ht +pol.ht +asso.ht +edu.ht +rel.ht +gouv.ht +perso.ht + +// hu : http://www.domain.hu/domain/English/sld.html +// Confirmed by registry 2008-06-12 +hu +co.hu +info.hu +org.hu +priv.hu +sport.hu +tm.hu +2000.hu +agrar.hu +bolt.hu +casino.hu +city.hu +erotica.hu +erotika.hu +film.hu +forum.hu +games.hu +hotel.hu +ingatlan.hu +jogasz.hu +konyvelo.hu +lakas.hu +media.hu +news.hu +reklam.hu +sex.hu +shop.hu +suli.hu +szex.hu +tozsde.hu +utazas.hu +video.hu + +// id : https://pandi.id/en/domain/registration-requirements/ +id +ac.id +biz.id +co.id +desa.id +go.id +mil.id +my.id +net.id +or.id +ponpes.id +sch.id +web.id + +// ie : https://en.wikipedia.org/wiki/.ie +ie +gov.ie + +// il : http://www.isoc.org.il/domains/ +il +ac.il +co.il +gov.il +idf.il +k12.il +muni.il +net.il +org.il + +// im : https://www.nic.im/ +// Submitted by registry +im +ac.im +co.im +com.im +ltd.co.im +net.im +org.im +plc.co.im +tt.im +tv.im + +// in : https://en.wikipedia.org/wiki/.in +// see also: https://registry.in/Policies +// Please note, that nic.in is not an official eTLD, but used by most +// government institutions. +in +co.in +firm.in +net.in +org.in +gen.in +ind.in +nic.in +ac.in +edu.in +res.in +gov.in +mil.in + +// info : https://en.wikipedia.org/wiki/.info +info + +// int : https://en.wikipedia.org/wiki/.int +// Confirmed by registry 2008-06-18 +int +eu.int + +// io : http://www.nic.io/rules.html +// list of other 2nd level tlds ? +io +com.io + +// iq : http://www.cmc.iq/english/iq/iqregister1.htm +iq +gov.iq +edu.iq +mil.iq +com.iq +org.iq +net.iq + +// ir : http://www.nic.ir/Terms_and_Conditions_ir,_Appendix_1_Domain_Rules +// Also see http://www.nic.ir/Internationalized_Domain_Names +// Two .ir entries added at request of , 2010-04-16 +ir +ac.ir +co.ir +gov.ir +id.ir +net.ir +org.ir +sch.ir +// xn--mgba3a4f16a.ir (.ir, Persian YEH) +ایران.ir +// xn--mgba3a4fra.ir (.ir, Arabic YEH) +ايران.ir + +// is : http://www.isnic.is/domain/rules.php +// Confirmed by registry 2008-12-06 +is +net.is +com.is +edu.is +gov.is +org.is +int.is + +// it : https://en.wikipedia.org/wiki/.it +it +gov.it +edu.it +// Reserved geo-names (regions and provinces): +// https://www.nic.it/sites/default/files/archivio/docs/Regulation_assignation_v7.1.pdf +// Regions +abr.it +abruzzo.it +aosta-valley.it +aostavalley.it +bas.it +basilicata.it +cal.it +calabria.it +cam.it +campania.it +emilia-romagna.it +emiliaromagna.it +emr.it +friuli-v-giulia.it +friuli-ve-giulia.it +friuli-vegiulia.it +friuli-venezia-giulia.it +friuli-veneziagiulia.it +friuli-vgiulia.it +friuliv-giulia.it +friulive-giulia.it +friulivegiulia.it +friulivenezia-giulia.it +friuliveneziagiulia.it +friulivgiulia.it +fvg.it +laz.it +lazio.it +lig.it +liguria.it +lom.it +lombardia.it +lombardy.it +lucania.it +mar.it +marche.it +mol.it +molise.it +piedmont.it +piemonte.it +pmn.it +pug.it +puglia.it +sar.it +sardegna.it +sardinia.it +sic.it +sicilia.it +sicily.it +taa.it +tos.it +toscana.it +trentin-sud-tirol.it +trentin-süd-tirol.it +trentin-sudtirol.it +trentin-südtirol.it +trentin-sued-tirol.it +trentin-suedtirol.it +trentino-a-adige.it +trentino-aadige.it +trentino-alto-adige.it +trentino-altoadige.it +trentino-s-tirol.it +trentino-stirol.it +trentino-sud-tirol.it +trentino-süd-tirol.it +trentino-sudtirol.it +trentino-südtirol.it +trentino-sued-tirol.it +trentino-suedtirol.it +trentino.it +trentinoa-adige.it +trentinoaadige.it +trentinoalto-adige.it +trentinoaltoadige.it +trentinos-tirol.it +trentinostirol.it +trentinosud-tirol.it +trentinosüd-tirol.it +trentinosudtirol.it +trentinosüdtirol.it +trentinosued-tirol.it +trentinosuedtirol.it +trentinsud-tirol.it +trentinsüd-tirol.it +trentinsudtirol.it +trentinsüdtirol.it +trentinsued-tirol.it +trentinsuedtirol.it +tuscany.it +umb.it +umbria.it +val-d-aosta.it +val-daosta.it +vald-aosta.it +valdaosta.it +valle-aosta.it +valle-d-aosta.it +valle-daosta.it +valleaosta.it +valled-aosta.it +valledaosta.it +vallee-aoste.it +vallée-aoste.it +vallee-d-aoste.it +vallée-d-aoste.it +valleeaoste.it +valléeaoste.it +valleedaoste.it +valléedaoste.it +vao.it +vda.it +ven.it +veneto.it +// Provinces +ag.it +agrigento.it +al.it +alessandria.it +alto-adige.it +altoadige.it +an.it +ancona.it +andria-barletta-trani.it +andria-trani-barletta.it +andriabarlettatrani.it +andriatranibarletta.it +ao.it +aosta.it +aoste.it +ap.it +aq.it +aquila.it +ar.it +arezzo.it +ascoli-piceno.it +ascolipiceno.it +asti.it +at.it +av.it +avellino.it +ba.it +balsan-sudtirol.it +balsan-südtirol.it +balsan-suedtirol.it +balsan.it +bari.it +barletta-trani-andria.it +barlettatraniandria.it +belluno.it +benevento.it +bergamo.it +bg.it +bi.it +biella.it +bl.it +bn.it +bo.it +bologna.it +bolzano-altoadige.it +bolzano.it +bozen-sudtirol.it +bozen-südtirol.it +bozen-suedtirol.it +bozen.it +br.it +brescia.it +brindisi.it +bs.it +bt.it +bulsan-sudtirol.it +bulsan-südtirol.it +bulsan-suedtirol.it +bulsan.it +bz.it +ca.it +cagliari.it +caltanissetta.it +campidano-medio.it +campidanomedio.it +campobasso.it +carbonia-iglesias.it +carboniaiglesias.it +carrara-massa.it +carraramassa.it +caserta.it +catania.it +catanzaro.it +cb.it +ce.it +cesena-forli.it +cesena-forlì.it +cesenaforli.it +cesenaforlì.it +ch.it +chieti.it +ci.it +cl.it +cn.it +co.it +como.it +cosenza.it +cr.it +cremona.it +crotone.it +cs.it +ct.it +cuneo.it +cz.it +dell-ogliastra.it +dellogliastra.it +en.it +enna.it +fc.it +fe.it +fermo.it +ferrara.it +fg.it +fi.it +firenze.it +florence.it +fm.it +foggia.it +forli-cesena.it +forlì-cesena.it +forlicesena.it +forlìcesena.it +fr.it +frosinone.it +ge.it +genoa.it +genova.it +go.it +gorizia.it +gr.it +grosseto.it +iglesias-carbonia.it +iglesiascarbonia.it +im.it +imperia.it +is.it +isernia.it +kr.it +la-spezia.it +laquila.it +laspezia.it +latina.it +lc.it +le.it +lecce.it +lecco.it +li.it +livorno.it +lo.it +lodi.it +lt.it +lu.it +lucca.it +macerata.it +mantova.it +massa-carrara.it +massacarrara.it +matera.it +mb.it +mc.it +me.it +medio-campidano.it +mediocampidano.it +messina.it +mi.it +milan.it +milano.it +mn.it +mo.it +modena.it +monza-brianza.it +monza-e-della-brianza.it +monza.it +monzabrianza.it +monzaebrianza.it +monzaedellabrianza.it +ms.it +mt.it +na.it +naples.it +napoli.it +no.it +novara.it +nu.it +nuoro.it +og.it +ogliastra.it +olbia-tempio.it +olbiatempio.it +or.it +oristano.it +ot.it +pa.it +padova.it +padua.it +palermo.it +parma.it +pavia.it +pc.it +pd.it +pe.it +perugia.it +pesaro-urbino.it +pesarourbino.it +pescara.it +pg.it +pi.it +piacenza.it +pisa.it +pistoia.it +pn.it +po.it +pordenone.it +potenza.it +pr.it +prato.it +pt.it +pu.it +pv.it +pz.it +ra.it +ragusa.it +ravenna.it +rc.it +re.it +reggio-calabria.it +reggio-emilia.it +reggiocalabria.it +reggioemilia.it +rg.it +ri.it +rieti.it +rimini.it +rm.it +rn.it +ro.it +roma.it +rome.it +rovigo.it +sa.it +salerno.it +sassari.it +savona.it +si.it +siena.it +siracusa.it +so.it +sondrio.it +sp.it +sr.it +ss.it +suedtirol.it +südtirol.it +sv.it +ta.it +taranto.it +te.it +tempio-olbia.it +tempioolbia.it +teramo.it +terni.it +tn.it +to.it +torino.it +tp.it +tr.it +trani-andria-barletta.it +trani-barletta-andria.it +traniandriabarletta.it +tranibarlettaandria.it +trapani.it +trento.it +treviso.it +trieste.it +ts.it +turin.it +tv.it +ud.it +udine.it +urbino-pesaro.it +urbinopesaro.it +va.it +varese.it +vb.it +vc.it +ve.it +venezia.it +venice.it +verbania.it +vercelli.it +verona.it +vi.it +vibo-valentia.it +vibovalentia.it +vicenza.it +viterbo.it +vr.it +vs.it +vt.it +vv.it + +// je : http://www.channelisles.net/register-domains/ +// Confirmed by registry 2013-11-28 +je +co.je +net.je +org.je + +// jm : http://www.com.jm/register.html +*.jm + +// jo : http://www.dns.jo/Registration_policy.aspx +jo +com.jo +org.jo +net.jo +edu.jo +sch.jo +gov.jo +mil.jo +name.jo + +// jobs : https://en.wikipedia.org/wiki/.jobs +jobs + +// jp : https://en.wikipedia.org/wiki/.jp +// http://jprs.co.jp/en/jpdomain.html +// Submitted by registry +jp +// jp organizational type names +ac.jp +ad.jp +co.jp +ed.jp +go.jp +gr.jp +lg.jp +ne.jp +or.jp +// jp prefecture type names +aichi.jp +akita.jp +aomori.jp +chiba.jp +ehime.jp +fukui.jp +fukuoka.jp +fukushima.jp +gifu.jp +gunma.jp +hiroshima.jp +hokkaido.jp +hyogo.jp +ibaraki.jp +ishikawa.jp +iwate.jp +kagawa.jp +kagoshima.jp +kanagawa.jp +kochi.jp +kumamoto.jp +kyoto.jp +mie.jp +miyagi.jp +miyazaki.jp +nagano.jp +nagasaki.jp +nara.jp +niigata.jp +oita.jp +okayama.jp +okinawa.jp +osaka.jp +saga.jp +saitama.jp +shiga.jp +shimane.jp +shizuoka.jp +tochigi.jp +tokushima.jp +tokyo.jp +tottori.jp +toyama.jp +wakayama.jp +yamagata.jp +yamaguchi.jp +yamanashi.jp +栃木.jp +愛知.jp +愛媛.jp +兵庫.jp +熊本.jp +茨城.jp +北海道.jp +千葉.jp +和歌山.jp +長崎.jp +長野.jp +新潟.jp +青森.jp +静岡.jp +東京.jp +石川.jp +埼玉.jp +三重.jp +京都.jp +佐賀.jp +大分.jp +大阪.jp +奈良.jp +宮城.jp +宮崎.jp +富山.jp +山口.jp +山形.jp +山梨.jp +岩手.jp +岐阜.jp +岡山.jp +島根.jp +広島.jp +徳島.jp +沖縄.jp +滋賀.jp +神奈川.jp +福井.jp +福岡.jp +福島.jp +秋田.jp +群馬.jp +香川.jp +高知.jp +鳥取.jp +鹿児島.jp +// jp geographic type names +// http://jprs.jp/doc/rule/saisoku-1.html +*.kawasaki.jp +*.kitakyushu.jp +*.kobe.jp +*.nagoya.jp +*.sapporo.jp +*.sendai.jp +*.yokohama.jp +!city.kawasaki.jp +!city.kitakyushu.jp +!city.kobe.jp +!city.nagoya.jp +!city.sapporo.jp +!city.sendai.jp +!city.yokohama.jp +// 4th level registration +aisai.aichi.jp +ama.aichi.jp +anjo.aichi.jp +asuke.aichi.jp +chiryu.aichi.jp +chita.aichi.jp +fuso.aichi.jp +gamagori.aichi.jp +handa.aichi.jp +hazu.aichi.jp +hekinan.aichi.jp +higashiura.aichi.jp +ichinomiya.aichi.jp +inazawa.aichi.jp +inuyama.aichi.jp +isshiki.aichi.jp +iwakura.aichi.jp +kanie.aichi.jp +kariya.aichi.jp +kasugai.aichi.jp +kira.aichi.jp +kiyosu.aichi.jp +komaki.aichi.jp +konan.aichi.jp +kota.aichi.jp +mihama.aichi.jp +miyoshi.aichi.jp +nishio.aichi.jp +nisshin.aichi.jp +obu.aichi.jp +oguchi.aichi.jp +oharu.aichi.jp +okazaki.aichi.jp +owariasahi.aichi.jp +seto.aichi.jp +shikatsu.aichi.jp +shinshiro.aichi.jp +shitara.aichi.jp +tahara.aichi.jp +takahama.aichi.jp +tobishima.aichi.jp +toei.aichi.jp +togo.aichi.jp +tokai.aichi.jp +tokoname.aichi.jp +toyoake.aichi.jp +toyohashi.aichi.jp +toyokawa.aichi.jp +toyone.aichi.jp +toyota.aichi.jp +tsushima.aichi.jp +yatomi.aichi.jp +akita.akita.jp +daisen.akita.jp +fujisato.akita.jp +gojome.akita.jp +hachirogata.akita.jp +happou.akita.jp +higashinaruse.akita.jp +honjo.akita.jp +honjyo.akita.jp +ikawa.akita.jp +kamikoani.akita.jp +kamioka.akita.jp +katagami.akita.jp +kazuno.akita.jp +kitaakita.akita.jp +kosaka.akita.jp +kyowa.akita.jp +misato.akita.jp +mitane.akita.jp +moriyoshi.akita.jp +nikaho.akita.jp +noshiro.akita.jp +odate.akita.jp +oga.akita.jp +ogata.akita.jp +semboku.akita.jp +yokote.akita.jp +yurihonjo.akita.jp +aomori.aomori.jp +gonohe.aomori.jp +hachinohe.aomori.jp +hashikami.aomori.jp +hiranai.aomori.jp +hirosaki.aomori.jp +itayanagi.aomori.jp +kuroishi.aomori.jp +misawa.aomori.jp +mutsu.aomori.jp +nakadomari.aomori.jp +noheji.aomori.jp +oirase.aomori.jp +owani.aomori.jp +rokunohe.aomori.jp +sannohe.aomori.jp +shichinohe.aomori.jp +shingo.aomori.jp +takko.aomori.jp +towada.aomori.jp +tsugaru.aomori.jp +tsuruta.aomori.jp +abiko.chiba.jp +asahi.chiba.jp +chonan.chiba.jp +chosei.chiba.jp +choshi.chiba.jp +chuo.chiba.jp +funabashi.chiba.jp +futtsu.chiba.jp +hanamigawa.chiba.jp +ichihara.chiba.jp +ichikawa.chiba.jp +ichinomiya.chiba.jp +inzai.chiba.jp +isumi.chiba.jp +kamagaya.chiba.jp +kamogawa.chiba.jp +kashiwa.chiba.jp +katori.chiba.jp +katsuura.chiba.jp +kimitsu.chiba.jp +kisarazu.chiba.jp +kozaki.chiba.jp +kujukuri.chiba.jp +kyonan.chiba.jp +matsudo.chiba.jp +midori.chiba.jp +mihama.chiba.jp +minamiboso.chiba.jp +mobara.chiba.jp +mutsuzawa.chiba.jp +nagara.chiba.jp +nagareyama.chiba.jp +narashino.chiba.jp +narita.chiba.jp +noda.chiba.jp +oamishirasato.chiba.jp +omigawa.chiba.jp +onjuku.chiba.jp +otaki.chiba.jp +sakae.chiba.jp +sakura.chiba.jp +shimofusa.chiba.jp +shirako.chiba.jp +shiroi.chiba.jp +shisui.chiba.jp +sodegaura.chiba.jp +sosa.chiba.jp +tako.chiba.jp +tateyama.chiba.jp +togane.chiba.jp +tohnosho.chiba.jp +tomisato.chiba.jp +urayasu.chiba.jp +yachimata.chiba.jp +yachiyo.chiba.jp +yokaichiba.chiba.jp +yokoshibahikari.chiba.jp +yotsukaido.chiba.jp +ainan.ehime.jp +honai.ehime.jp +ikata.ehime.jp +imabari.ehime.jp +iyo.ehime.jp +kamijima.ehime.jp +kihoku.ehime.jp +kumakogen.ehime.jp +masaki.ehime.jp +matsuno.ehime.jp +matsuyama.ehime.jp +namikata.ehime.jp +niihama.ehime.jp +ozu.ehime.jp +saijo.ehime.jp +seiyo.ehime.jp +shikokuchuo.ehime.jp +tobe.ehime.jp +toon.ehime.jp +uchiko.ehime.jp +uwajima.ehime.jp +yawatahama.ehime.jp +echizen.fukui.jp +eiheiji.fukui.jp +fukui.fukui.jp +ikeda.fukui.jp +katsuyama.fukui.jp +mihama.fukui.jp +minamiechizen.fukui.jp +obama.fukui.jp +ohi.fukui.jp +ono.fukui.jp +sabae.fukui.jp +sakai.fukui.jp +takahama.fukui.jp +tsuruga.fukui.jp +wakasa.fukui.jp +ashiya.fukuoka.jp +buzen.fukuoka.jp +chikugo.fukuoka.jp +chikuho.fukuoka.jp +chikujo.fukuoka.jp +chikushino.fukuoka.jp +chikuzen.fukuoka.jp +chuo.fukuoka.jp +dazaifu.fukuoka.jp +fukuchi.fukuoka.jp +hakata.fukuoka.jp +higashi.fukuoka.jp +hirokawa.fukuoka.jp +hisayama.fukuoka.jp +iizuka.fukuoka.jp +inatsuki.fukuoka.jp +kaho.fukuoka.jp +kasuga.fukuoka.jp +kasuya.fukuoka.jp +kawara.fukuoka.jp +keisen.fukuoka.jp +koga.fukuoka.jp +kurate.fukuoka.jp +kurogi.fukuoka.jp +kurume.fukuoka.jp +minami.fukuoka.jp +miyako.fukuoka.jp +miyama.fukuoka.jp +miyawaka.fukuoka.jp +mizumaki.fukuoka.jp +munakata.fukuoka.jp +nakagawa.fukuoka.jp +nakama.fukuoka.jp +nishi.fukuoka.jp +nogata.fukuoka.jp +ogori.fukuoka.jp +okagaki.fukuoka.jp +okawa.fukuoka.jp +oki.fukuoka.jp +omuta.fukuoka.jp +onga.fukuoka.jp +onojo.fukuoka.jp +oto.fukuoka.jp +saigawa.fukuoka.jp +sasaguri.fukuoka.jp +shingu.fukuoka.jp +shinyoshitomi.fukuoka.jp +shonai.fukuoka.jp +soeda.fukuoka.jp +sue.fukuoka.jp +tachiarai.fukuoka.jp +tagawa.fukuoka.jp +takata.fukuoka.jp +toho.fukuoka.jp +toyotsu.fukuoka.jp +tsuiki.fukuoka.jp +ukiha.fukuoka.jp +umi.fukuoka.jp +usui.fukuoka.jp +yamada.fukuoka.jp +yame.fukuoka.jp +yanagawa.fukuoka.jp +yukuhashi.fukuoka.jp +aizubange.fukushima.jp +aizumisato.fukushima.jp +aizuwakamatsu.fukushima.jp +asakawa.fukushima.jp +bandai.fukushima.jp +date.fukushima.jp +fukushima.fukushima.jp +furudono.fukushima.jp +futaba.fukushima.jp +hanawa.fukushima.jp +higashi.fukushima.jp +hirata.fukushima.jp +hirono.fukushima.jp +iitate.fukushima.jp +inawashiro.fukushima.jp +ishikawa.fukushima.jp +iwaki.fukushima.jp +izumizaki.fukushima.jp +kagamiishi.fukushima.jp +kaneyama.fukushima.jp +kawamata.fukushima.jp +kitakata.fukushima.jp +kitashiobara.fukushima.jp +koori.fukushima.jp +koriyama.fukushima.jp +kunimi.fukushima.jp +miharu.fukushima.jp +mishima.fukushima.jp +namie.fukushima.jp +nango.fukushima.jp +nishiaizu.fukushima.jp +nishigo.fukushima.jp +okuma.fukushima.jp +omotego.fukushima.jp +ono.fukushima.jp +otama.fukushima.jp +samegawa.fukushima.jp +shimogo.fukushima.jp +shirakawa.fukushima.jp +showa.fukushima.jp +soma.fukushima.jp +sukagawa.fukushima.jp +taishin.fukushima.jp +tamakawa.fukushima.jp +tanagura.fukushima.jp +tenei.fukushima.jp +yabuki.fukushima.jp +yamato.fukushima.jp +yamatsuri.fukushima.jp +yanaizu.fukushima.jp +yugawa.fukushima.jp +anpachi.gifu.jp +ena.gifu.jp +gifu.gifu.jp +ginan.gifu.jp +godo.gifu.jp +gujo.gifu.jp +hashima.gifu.jp +hichiso.gifu.jp +hida.gifu.jp +higashishirakawa.gifu.jp +ibigawa.gifu.jp +ikeda.gifu.jp +kakamigahara.gifu.jp +kani.gifu.jp +kasahara.gifu.jp +kasamatsu.gifu.jp +kawaue.gifu.jp +kitagata.gifu.jp +mino.gifu.jp +minokamo.gifu.jp +mitake.gifu.jp +mizunami.gifu.jp +motosu.gifu.jp +nakatsugawa.gifu.jp +ogaki.gifu.jp +sakahogi.gifu.jp +seki.gifu.jp +sekigahara.gifu.jp +shirakawa.gifu.jp +tajimi.gifu.jp +takayama.gifu.jp +tarui.gifu.jp +toki.gifu.jp +tomika.gifu.jp +wanouchi.gifu.jp +yamagata.gifu.jp +yaotsu.gifu.jp +yoro.gifu.jp +annaka.gunma.jp +chiyoda.gunma.jp +fujioka.gunma.jp +higashiagatsuma.gunma.jp +isesaki.gunma.jp +itakura.gunma.jp +kanna.gunma.jp +kanra.gunma.jp +katashina.gunma.jp +kawaba.gunma.jp +kiryu.gunma.jp +kusatsu.gunma.jp +maebashi.gunma.jp +meiwa.gunma.jp +midori.gunma.jp +minakami.gunma.jp +naganohara.gunma.jp +nakanojo.gunma.jp +nanmoku.gunma.jp +numata.gunma.jp +oizumi.gunma.jp +ora.gunma.jp +ota.gunma.jp +shibukawa.gunma.jp +shimonita.gunma.jp +shinto.gunma.jp +showa.gunma.jp +takasaki.gunma.jp +takayama.gunma.jp +tamamura.gunma.jp +tatebayashi.gunma.jp +tomioka.gunma.jp +tsukiyono.gunma.jp +tsumagoi.gunma.jp +ueno.gunma.jp +yoshioka.gunma.jp +asaminami.hiroshima.jp +daiwa.hiroshima.jp +etajima.hiroshima.jp +fuchu.hiroshima.jp +fukuyama.hiroshima.jp +hatsukaichi.hiroshima.jp +higashihiroshima.hiroshima.jp +hongo.hiroshima.jp +jinsekikogen.hiroshima.jp +kaita.hiroshima.jp +kui.hiroshima.jp +kumano.hiroshima.jp +kure.hiroshima.jp +mihara.hiroshima.jp +miyoshi.hiroshima.jp +naka.hiroshima.jp +onomichi.hiroshima.jp +osakikamijima.hiroshima.jp +otake.hiroshima.jp +saka.hiroshima.jp +sera.hiroshima.jp +seranishi.hiroshima.jp +shinichi.hiroshima.jp +shobara.hiroshima.jp +takehara.hiroshima.jp +abashiri.hokkaido.jp +abira.hokkaido.jp +aibetsu.hokkaido.jp +akabira.hokkaido.jp +akkeshi.hokkaido.jp +asahikawa.hokkaido.jp +ashibetsu.hokkaido.jp +ashoro.hokkaido.jp +assabu.hokkaido.jp +atsuma.hokkaido.jp +bibai.hokkaido.jp +biei.hokkaido.jp +bifuka.hokkaido.jp +bihoro.hokkaido.jp +biratori.hokkaido.jp +chippubetsu.hokkaido.jp +chitose.hokkaido.jp +date.hokkaido.jp +ebetsu.hokkaido.jp +embetsu.hokkaido.jp +eniwa.hokkaido.jp +erimo.hokkaido.jp +esan.hokkaido.jp +esashi.hokkaido.jp +fukagawa.hokkaido.jp +fukushima.hokkaido.jp +furano.hokkaido.jp +furubira.hokkaido.jp +haboro.hokkaido.jp +hakodate.hokkaido.jp +hamatonbetsu.hokkaido.jp +hidaka.hokkaido.jp +higashikagura.hokkaido.jp +higashikawa.hokkaido.jp +hiroo.hokkaido.jp +hokuryu.hokkaido.jp +hokuto.hokkaido.jp +honbetsu.hokkaido.jp +horokanai.hokkaido.jp +horonobe.hokkaido.jp +ikeda.hokkaido.jp +imakane.hokkaido.jp +ishikari.hokkaido.jp +iwamizawa.hokkaido.jp +iwanai.hokkaido.jp +kamifurano.hokkaido.jp +kamikawa.hokkaido.jp +kamishihoro.hokkaido.jp +kamisunagawa.hokkaido.jp +kamoenai.hokkaido.jp +kayabe.hokkaido.jp +kembuchi.hokkaido.jp +kikonai.hokkaido.jp +kimobetsu.hokkaido.jp +kitahiroshima.hokkaido.jp +kitami.hokkaido.jp +kiyosato.hokkaido.jp +koshimizu.hokkaido.jp +kunneppu.hokkaido.jp +kuriyama.hokkaido.jp +kuromatsunai.hokkaido.jp +kushiro.hokkaido.jp +kutchan.hokkaido.jp +kyowa.hokkaido.jp +mashike.hokkaido.jp +matsumae.hokkaido.jp +mikasa.hokkaido.jp +minamifurano.hokkaido.jp +mombetsu.hokkaido.jp +moseushi.hokkaido.jp +mukawa.hokkaido.jp +muroran.hokkaido.jp +naie.hokkaido.jp +nakagawa.hokkaido.jp +nakasatsunai.hokkaido.jp +nakatombetsu.hokkaido.jp +nanae.hokkaido.jp +nanporo.hokkaido.jp +nayoro.hokkaido.jp +nemuro.hokkaido.jp +niikappu.hokkaido.jp +niki.hokkaido.jp +nishiokoppe.hokkaido.jp +noboribetsu.hokkaido.jp +numata.hokkaido.jp +obihiro.hokkaido.jp +obira.hokkaido.jp +oketo.hokkaido.jp +okoppe.hokkaido.jp +otaru.hokkaido.jp +otobe.hokkaido.jp +otofuke.hokkaido.jp +otoineppu.hokkaido.jp +oumu.hokkaido.jp +ozora.hokkaido.jp +pippu.hokkaido.jp +rankoshi.hokkaido.jp +rebun.hokkaido.jp +rikubetsu.hokkaido.jp +rishiri.hokkaido.jp +rishirifuji.hokkaido.jp +saroma.hokkaido.jp +sarufutsu.hokkaido.jp +shakotan.hokkaido.jp +shari.hokkaido.jp +shibecha.hokkaido.jp +shibetsu.hokkaido.jp +shikabe.hokkaido.jp +shikaoi.hokkaido.jp +shimamaki.hokkaido.jp +shimizu.hokkaido.jp +shimokawa.hokkaido.jp +shinshinotsu.hokkaido.jp +shintoku.hokkaido.jp +shiranuka.hokkaido.jp +shiraoi.hokkaido.jp +shiriuchi.hokkaido.jp +sobetsu.hokkaido.jp +sunagawa.hokkaido.jp +taiki.hokkaido.jp +takasu.hokkaido.jp +takikawa.hokkaido.jp +takinoue.hokkaido.jp +teshikaga.hokkaido.jp +tobetsu.hokkaido.jp +tohma.hokkaido.jp +tomakomai.hokkaido.jp +tomari.hokkaido.jp +toya.hokkaido.jp +toyako.hokkaido.jp +toyotomi.hokkaido.jp +toyoura.hokkaido.jp +tsubetsu.hokkaido.jp +tsukigata.hokkaido.jp +urakawa.hokkaido.jp +urausu.hokkaido.jp +uryu.hokkaido.jp +utashinai.hokkaido.jp +wakkanai.hokkaido.jp +wassamu.hokkaido.jp +yakumo.hokkaido.jp +yoichi.hokkaido.jp +aioi.hyogo.jp +akashi.hyogo.jp +ako.hyogo.jp +amagasaki.hyogo.jp +aogaki.hyogo.jp +asago.hyogo.jp +ashiya.hyogo.jp +awaji.hyogo.jp +fukusaki.hyogo.jp +goshiki.hyogo.jp +harima.hyogo.jp +himeji.hyogo.jp +ichikawa.hyogo.jp +inagawa.hyogo.jp +itami.hyogo.jp +kakogawa.hyogo.jp +kamigori.hyogo.jp +kamikawa.hyogo.jp +kasai.hyogo.jp +kasuga.hyogo.jp +kawanishi.hyogo.jp +miki.hyogo.jp +minamiawaji.hyogo.jp +nishinomiya.hyogo.jp +nishiwaki.hyogo.jp +ono.hyogo.jp +sanda.hyogo.jp +sannan.hyogo.jp +sasayama.hyogo.jp +sayo.hyogo.jp +shingu.hyogo.jp +shinonsen.hyogo.jp +shiso.hyogo.jp +sumoto.hyogo.jp +taishi.hyogo.jp +taka.hyogo.jp +takarazuka.hyogo.jp +takasago.hyogo.jp +takino.hyogo.jp +tamba.hyogo.jp +tatsuno.hyogo.jp +toyooka.hyogo.jp +yabu.hyogo.jp +yashiro.hyogo.jp +yoka.hyogo.jp +yokawa.hyogo.jp +ami.ibaraki.jp +asahi.ibaraki.jp +bando.ibaraki.jp +chikusei.ibaraki.jp +daigo.ibaraki.jp +fujishiro.ibaraki.jp +hitachi.ibaraki.jp +hitachinaka.ibaraki.jp +hitachiomiya.ibaraki.jp +hitachiota.ibaraki.jp +ibaraki.ibaraki.jp +ina.ibaraki.jp +inashiki.ibaraki.jp +itako.ibaraki.jp +iwama.ibaraki.jp +joso.ibaraki.jp +kamisu.ibaraki.jp +kasama.ibaraki.jp +kashima.ibaraki.jp +kasumigaura.ibaraki.jp +koga.ibaraki.jp +miho.ibaraki.jp +mito.ibaraki.jp +moriya.ibaraki.jp +naka.ibaraki.jp +namegata.ibaraki.jp +oarai.ibaraki.jp +ogawa.ibaraki.jp +omitama.ibaraki.jp +ryugasaki.ibaraki.jp +sakai.ibaraki.jp +sakuragawa.ibaraki.jp +shimodate.ibaraki.jp +shimotsuma.ibaraki.jp +shirosato.ibaraki.jp +sowa.ibaraki.jp +suifu.ibaraki.jp +takahagi.ibaraki.jp +tamatsukuri.ibaraki.jp +tokai.ibaraki.jp +tomobe.ibaraki.jp +tone.ibaraki.jp +toride.ibaraki.jp +tsuchiura.ibaraki.jp +tsukuba.ibaraki.jp +uchihara.ibaraki.jp +ushiku.ibaraki.jp +yachiyo.ibaraki.jp +yamagata.ibaraki.jp +yawara.ibaraki.jp +yuki.ibaraki.jp +anamizu.ishikawa.jp +hakui.ishikawa.jp +hakusan.ishikawa.jp +kaga.ishikawa.jp +kahoku.ishikawa.jp +kanazawa.ishikawa.jp +kawakita.ishikawa.jp +komatsu.ishikawa.jp +nakanoto.ishikawa.jp +nanao.ishikawa.jp +nomi.ishikawa.jp +nonoichi.ishikawa.jp +noto.ishikawa.jp +shika.ishikawa.jp +suzu.ishikawa.jp +tsubata.ishikawa.jp +tsurugi.ishikawa.jp +uchinada.ishikawa.jp +wajima.ishikawa.jp +fudai.iwate.jp +fujisawa.iwate.jp +hanamaki.iwate.jp +hiraizumi.iwate.jp +hirono.iwate.jp +ichinohe.iwate.jp +ichinoseki.iwate.jp +iwaizumi.iwate.jp +iwate.iwate.jp +joboji.iwate.jp +kamaishi.iwate.jp +kanegasaki.iwate.jp +karumai.iwate.jp +kawai.iwate.jp +kitakami.iwate.jp +kuji.iwate.jp +kunohe.iwate.jp +kuzumaki.iwate.jp +miyako.iwate.jp +mizusawa.iwate.jp +morioka.iwate.jp +ninohe.iwate.jp +noda.iwate.jp +ofunato.iwate.jp +oshu.iwate.jp +otsuchi.iwate.jp +rikuzentakata.iwate.jp +shiwa.iwate.jp +shizukuishi.iwate.jp +sumita.iwate.jp +tanohata.iwate.jp +tono.iwate.jp +yahaba.iwate.jp +yamada.iwate.jp +ayagawa.kagawa.jp +higashikagawa.kagawa.jp +kanonji.kagawa.jp +kotohira.kagawa.jp +manno.kagawa.jp +marugame.kagawa.jp +mitoyo.kagawa.jp +naoshima.kagawa.jp +sanuki.kagawa.jp +tadotsu.kagawa.jp +takamatsu.kagawa.jp +tonosho.kagawa.jp +uchinomi.kagawa.jp +utazu.kagawa.jp +zentsuji.kagawa.jp +akune.kagoshima.jp +amami.kagoshima.jp +hioki.kagoshima.jp +isa.kagoshima.jp +isen.kagoshima.jp +izumi.kagoshima.jp +kagoshima.kagoshima.jp +kanoya.kagoshima.jp +kawanabe.kagoshima.jp +kinko.kagoshima.jp +kouyama.kagoshima.jp +makurazaki.kagoshima.jp +matsumoto.kagoshima.jp +minamitane.kagoshima.jp +nakatane.kagoshima.jp +nishinoomote.kagoshima.jp +satsumasendai.kagoshima.jp +soo.kagoshima.jp +tarumizu.kagoshima.jp +yusui.kagoshima.jp +aikawa.kanagawa.jp +atsugi.kanagawa.jp +ayase.kanagawa.jp +chigasaki.kanagawa.jp +ebina.kanagawa.jp +fujisawa.kanagawa.jp +hadano.kanagawa.jp +hakone.kanagawa.jp +hiratsuka.kanagawa.jp +isehara.kanagawa.jp +kaisei.kanagawa.jp +kamakura.kanagawa.jp +kiyokawa.kanagawa.jp +matsuda.kanagawa.jp +minamiashigara.kanagawa.jp +miura.kanagawa.jp +nakai.kanagawa.jp +ninomiya.kanagawa.jp +odawara.kanagawa.jp +oi.kanagawa.jp +oiso.kanagawa.jp +sagamihara.kanagawa.jp +samukawa.kanagawa.jp +tsukui.kanagawa.jp +yamakita.kanagawa.jp +yamato.kanagawa.jp +yokosuka.kanagawa.jp +yugawara.kanagawa.jp +zama.kanagawa.jp +zushi.kanagawa.jp +aki.kochi.jp +geisei.kochi.jp +hidaka.kochi.jp +higashitsuno.kochi.jp +ino.kochi.jp +kagami.kochi.jp +kami.kochi.jp +kitagawa.kochi.jp +kochi.kochi.jp +mihara.kochi.jp +motoyama.kochi.jp +muroto.kochi.jp +nahari.kochi.jp +nakamura.kochi.jp +nankoku.kochi.jp +nishitosa.kochi.jp +niyodogawa.kochi.jp +ochi.kochi.jp +okawa.kochi.jp +otoyo.kochi.jp +otsuki.kochi.jp +sakawa.kochi.jp +sukumo.kochi.jp +susaki.kochi.jp +tosa.kochi.jp +tosashimizu.kochi.jp +toyo.kochi.jp +tsuno.kochi.jp +umaji.kochi.jp +yasuda.kochi.jp +yusuhara.kochi.jp +amakusa.kumamoto.jp +arao.kumamoto.jp +aso.kumamoto.jp +choyo.kumamoto.jp +gyokuto.kumamoto.jp +kamiamakusa.kumamoto.jp +kikuchi.kumamoto.jp +kumamoto.kumamoto.jp +mashiki.kumamoto.jp +mifune.kumamoto.jp +minamata.kumamoto.jp +minamioguni.kumamoto.jp +nagasu.kumamoto.jp +nishihara.kumamoto.jp +oguni.kumamoto.jp +ozu.kumamoto.jp +sumoto.kumamoto.jp +takamori.kumamoto.jp +uki.kumamoto.jp +uto.kumamoto.jp +yamaga.kumamoto.jp +yamato.kumamoto.jp +yatsushiro.kumamoto.jp +ayabe.kyoto.jp +fukuchiyama.kyoto.jp +higashiyama.kyoto.jp +ide.kyoto.jp +ine.kyoto.jp +joyo.kyoto.jp +kameoka.kyoto.jp +kamo.kyoto.jp +kita.kyoto.jp +kizu.kyoto.jp +kumiyama.kyoto.jp +kyotamba.kyoto.jp +kyotanabe.kyoto.jp +kyotango.kyoto.jp +maizuru.kyoto.jp +minami.kyoto.jp +minamiyamashiro.kyoto.jp +miyazu.kyoto.jp +muko.kyoto.jp +nagaokakyo.kyoto.jp +nakagyo.kyoto.jp +nantan.kyoto.jp +oyamazaki.kyoto.jp +sakyo.kyoto.jp +seika.kyoto.jp +tanabe.kyoto.jp +uji.kyoto.jp +ujitawara.kyoto.jp +wazuka.kyoto.jp +yamashina.kyoto.jp +yawata.kyoto.jp +asahi.mie.jp +inabe.mie.jp +ise.mie.jp +kameyama.mie.jp +kawagoe.mie.jp +kiho.mie.jp +kisosaki.mie.jp +kiwa.mie.jp +komono.mie.jp +kumano.mie.jp +kuwana.mie.jp +matsusaka.mie.jp +meiwa.mie.jp +mihama.mie.jp +minamiise.mie.jp +misugi.mie.jp +miyama.mie.jp +nabari.mie.jp +shima.mie.jp +suzuka.mie.jp +tado.mie.jp +taiki.mie.jp +taki.mie.jp +tamaki.mie.jp +toba.mie.jp +tsu.mie.jp +udono.mie.jp +ureshino.mie.jp +watarai.mie.jp +yokkaichi.mie.jp +furukawa.miyagi.jp +higashimatsushima.miyagi.jp +ishinomaki.miyagi.jp +iwanuma.miyagi.jp +kakuda.miyagi.jp +kami.miyagi.jp +kawasaki.miyagi.jp +marumori.miyagi.jp +matsushima.miyagi.jp +minamisanriku.miyagi.jp +misato.miyagi.jp +murata.miyagi.jp +natori.miyagi.jp +ogawara.miyagi.jp +ohira.miyagi.jp +onagawa.miyagi.jp +osaki.miyagi.jp +rifu.miyagi.jp +semine.miyagi.jp +shibata.miyagi.jp +shichikashuku.miyagi.jp +shikama.miyagi.jp +shiogama.miyagi.jp +shiroishi.miyagi.jp +tagajo.miyagi.jp +taiwa.miyagi.jp +tome.miyagi.jp +tomiya.miyagi.jp +wakuya.miyagi.jp +watari.miyagi.jp +yamamoto.miyagi.jp +zao.miyagi.jp +aya.miyazaki.jp +ebino.miyazaki.jp +gokase.miyazaki.jp +hyuga.miyazaki.jp +kadogawa.miyazaki.jp +kawaminami.miyazaki.jp +kijo.miyazaki.jp +kitagawa.miyazaki.jp +kitakata.miyazaki.jp +kitaura.miyazaki.jp +kobayashi.miyazaki.jp +kunitomi.miyazaki.jp +kushima.miyazaki.jp +mimata.miyazaki.jp +miyakonojo.miyazaki.jp +miyazaki.miyazaki.jp +morotsuka.miyazaki.jp +nichinan.miyazaki.jp +nishimera.miyazaki.jp +nobeoka.miyazaki.jp +saito.miyazaki.jp +shiiba.miyazaki.jp +shintomi.miyazaki.jp +takaharu.miyazaki.jp +takanabe.miyazaki.jp +takazaki.miyazaki.jp +tsuno.miyazaki.jp +achi.nagano.jp +agematsu.nagano.jp +anan.nagano.jp +aoki.nagano.jp +asahi.nagano.jp +azumino.nagano.jp +chikuhoku.nagano.jp +chikuma.nagano.jp +chino.nagano.jp +fujimi.nagano.jp +hakuba.nagano.jp +hara.nagano.jp +hiraya.nagano.jp +iida.nagano.jp +iijima.nagano.jp +iiyama.nagano.jp +iizuna.nagano.jp +ikeda.nagano.jp +ikusaka.nagano.jp +ina.nagano.jp +karuizawa.nagano.jp +kawakami.nagano.jp +kiso.nagano.jp +kisofukushima.nagano.jp +kitaaiki.nagano.jp +komagane.nagano.jp +komoro.nagano.jp +matsukawa.nagano.jp +matsumoto.nagano.jp +miasa.nagano.jp +minamiaiki.nagano.jp +minamimaki.nagano.jp +minamiminowa.nagano.jp +minowa.nagano.jp +miyada.nagano.jp +miyota.nagano.jp +mochizuki.nagano.jp +nagano.nagano.jp +nagawa.nagano.jp +nagiso.nagano.jp +nakagawa.nagano.jp +nakano.nagano.jp +nozawaonsen.nagano.jp +obuse.nagano.jp +ogawa.nagano.jp +okaya.nagano.jp +omachi.nagano.jp +omi.nagano.jp +ookuwa.nagano.jp +ooshika.nagano.jp +otaki.nagano.jp +otari.nagano.jp +sakae.nagano.jp +sakaki.nagano.jp +saku.nagano.jp +sakuho.nagano.jp +shimosuwa.nagano.jp +shinanomachi.nagano.jp +shiojiri.nagano.jp +suwa.nagano.jp +suzaka.nagano.jp +takagi.nagano.jp +takamori.nagano.jp +takayama.nagano.jp +tateshina.nagano.jp +tatsuno.nagano.jp +togakushi.nagano.jp +togura.nagano.jp +tomi.nagano.jp +ueda.nagano.jp +wada.nagano.jp +yamagata.nagano.jp +yamanouchi.nagano.jp +yasaka.nagano.jp +yasuoka.nagano.jp +chijiwa.nagasaki.jp +futsu.nagasaki.jp +goto.nagasaki.jp +hasami.nagasaki.jp +hirado.nagasaki.jp +iki.nagasaki.jp +isahaya.nagasaki.jp +kawatana.nagasaki.jp +kuchinotsu.nagasaki.jp +matsuura.nagasaki.jp +nagasaki.nagasaki.jp +obama.nagasaki.jp +omura.nagasaki.jp +oseto.nagasaki.jp +saikai.nagasaki.jp +sasebo.nagasaki.jp +seihi.nagasaki.jp +shimabara.nagasaki.jp +shinkamigoto.nagasaki.jp +togitsu.nagasaki.jp +tsushima.nagasaki.jp +unzen.nagasaki.jp +ando.nara.jp +gose.nara.jp +heguri.nara.jp +higashiyoshino.nara.jp +ikaruga.nara.jp +ikoma.nara.jp +kamikitayama.nara.jp +kanmaki.nara.jp +kashiba.nara.jp +kashihara.nara.jp +katsuragi.nara.jp +kawai.nara.jp +kawakami.nara.jp +kawanishi.nara.jp +koryo.nara.jp +kurotaki.nara.jp +mitsue.nara.jp +miyake.nara.jp +nara.nara.jp +nosegawa.nara.jp +oji.nara.jp +ouda.nara.jp +oyodo.nara.jp +sakurai.nara.jp +sango.nara.jp +shimoichi.nara.jp +shimokitayama.nara.jp +shinjo.nara.jp +soni.nara.jp +takatori.nara.jp +tawaramoto.nara.jp +tenkawa.nara.jp +tenri.nara.jp +uda.nara.jp +yamatokoriyama.nara.jp +yamatotakada.nara.jp +yamazoe.nara.jp +yoshino.nara.jp +aga.niigata.jp +agano.niigata.jp +gosen.niigata.jp +itoigawa.niigata.jp +izumozaki.niigata.jp +joetsu.niigata.jp +kamo.niigata.jp +kariwa.niigata.jp +kashiwazaki.niigata.jp +minamiuonuma.niigata.jp +mitsuke.niigata.jp +muika.niigata.jp +murakami.niigata.jp +myoko.niigata.jp +nagaoka.niigata.jp +niigata.niigata.jp +ojiya.niigata.jp +omi.niigata.jp +sado.niigata.jp +sanjo.niigata.jp +seiro.niigata.jp +seirou.niigata.jp +sekikawa.niigata.jp +shibata.niigata.jp +tagami.niigata.jp +tainai.niigata.jp +tochio.niigata.jp +tokamachi.niigata.jp +tsubame.niigata.jp +tsunan.niigata.jp +uonuma.niigata.jp +yahiko.niigata.jp +yoita.niigata.jp +yuzawa.niigata.jp +beppu.oita.jp +bungoono.oita.jp +bungotakada.oita.jp +hasama.oita.jp +hiji.oita.jp +himeshima.oita.jp +hita.oita.jp +kamitsue.oita.jp +kokonoe.oita.jp +kuju.oita.jp +kunisaki.oita.jp +kusu.oita.jp +oita.oita.jp +saiki.oita.jp +taketa.oita.jp +tsukumi.oita.jp +usa.oita.jp +usuki.oita.jp +yufu.oita.jp +akaiwa.okayama.jp +asakuchi.okayama.jp +bizen.okayama.jp +hayashima.okayama.jp +ibara.okayama.jp +kagamino.okayama.jp +kasaoka.okayama.jp +kibichuo.okayama.jp +kumenan.okayama.jp +kurashiki.okayama.jp +maniwa.okayama.jp +misaki.okayama.jp +nagi.okayama.jp +niimi.okayama.jp +nishiawakura.okayama.jp +okayama.okayama.jp +satosho.okayama.jp +setouchi.okayama.jp +shinjo.okayama.jp +shoo.okayama.jp +soja.okayama.jp +takahashi.okayama.jp +tamano.okayama.jp +tsuyama.okayama.jp +wake.okayama.jp +yakage.okayama.jp +aguni.okinawa.jp +ginowan.okinawa.jp +ginoza.okinawa.jp +gushikami.okinawa.jp +haebaru.okinawa.jp +higashi.okinawa.jp +hirara.okinawa.jp +iheya.okinawa.jp +ishigaki.okinawa.jp +ishikawa.okinawa.jp +itoman.okinawa.jp +izena.okinawa.jp +kadena.okinawa.jp +kin.okinawa.jp +kitadaito.okinawa.jp +kitanakagusuku.okinawa.jp +kumejima.okinawa.jp +kunigami.okinawa.jp +minamidaito.okinawa.jp +motobu.okinawa.jp +nago.okinawa.jp +naha.okinawa.jp +nakagusuku.okinawa.jp +nakijin.okinawa.jp +nanjo.okinawa.jp +nishihara.okinawa.jp +ogimi.okinawa.jp +okinawa.okinawa.jp +onna.okinawa.jp +shimoji.okinawa.jp +taketomi.okinawa.jp +tarama.okinawa.jp +tokashiki.okinawa.jp +tomigusuku.okinawa.jp +tonaki.okinawa.jp +urasoe.okinawa.jp +uruma.okinawa.jp +yaese.okinawa.jp +yomitan.okinawa.jp +yonabaru.okinawa.jp +yonaguni.okinawa.jp +zamami.okinawa.jp +abeno.osaka.jp +chihayaakasaka.osaka.jp +chuo.osaka.jp +daito.osaka.jp +fujiidera.osaka.jp +habikino.osaka.jp +hannan.osaka.jp +higashiosaka.osaka.jp +higashisumiyoshi.osaka.jp +higashiyodogawa.osaka.jp +hirakata.osaka.jp +ibaraki.osaka.jp +ikeda.osaka.jp +izumi.osaka.jp +izumiotsu.osaka.jp +izumisano.osaka.jp +kadoma.osaka.jp +kaizuka.osaka.jp +kanan.osaka.jp +kashiwara.osaka.jp +katano.osaka.jp +kawachinagano.osaka.jp +kishiwada.osaka.jp +kita.osaka.jp +kumatori.osaka.jp +matsubara.osaka.jp +minato.osaka.jp +minoh.osaka.jp +misaki.osaka.jp +moriguchi.osaka.jp +neyagawa.osaka.jp +nishi.osaka.jp +nose.osaka.jp +osakasayama.osaka.jp +sakai.osaka.jp +sayama.osaka.jp +sennan.osaka.jp +settsu.osaka.jp +shijonawate.osaka.jp +shimamoto.osaka.jp +suita.osaka.jp +tadaoka.osaka.jp +taishi.osaka.jp +tajiri.osaka.jp +takaishi.osaka.jp +takatsuki.osaka.jp +tondabayashi.osaka.jp +toyonaka.osaka.jp +toyono.osaka.jp +yao.osaka.jp +ariake.saga.jp +arita.saga.jp +fukudomi.saga.jp +genkai.saga.jp +hamatama.saga.jp +hizen.saga.jp +imari.saga.jp +kamimine.saga.jp +kanzaki.saga.jp +karatsu.saga.jp +kashima.saga.jp +kitagata.saga.jp +kitahata.saga.jp +kiyama.saga.jp +kouhoku.saga.jp +kyuragi.saga.jp +nishiarita.saga.jp +ogi.saga.jp +omachi.saga.jp +ouchi.saga.jp +saga.saga.jp +shiroishi.saga.jp +taku.saga.jp +tara.saga.jp +tosu.saga.jp +yoshinogari.saga.jp +arakawa.saitama.jp +asaka.saitama.jp +chichibu.saitama.jp +fujimi.saitama.jp +fujimino.saitama.jp +fukaya.saitama.jp +hanno.saitama.jp +hanyu.saitama.jp +hasuda.saitama.jp +hatogaya.saitama.jp +hatoyama.saitama.jp +hidaka.saitama.jp +higashichichibu.saitama.jp +higashimatsuyama.saitama.jp +honjo.saitama.jp +ina.saitama.jp +iruma.saitama.jp +iwatsuki.saitama.jp +kamiizumi.saitama.jp +kamikawa.saitama.jp +kamisato.saitama.jp +kasukabe.saitama.jp +kawagoe.saitama.jp +kawaguchi.saitama.jp +kawajima.saitama.jp +kazo.saitama.jp +kitamoto.saitama.jp +koshigaya.saitama.jp +kounosu.saitama.jp +kuki.saitama.jp +kumagaya.saitama.jp +matsubushi.saitama.jp +minano.saitama.jp +misato.saitama.jp +miyashiro.saitama.jp +miyoshi.saitama.jp +moroyama.saitama.jp +nagatoro.saitama.jp +namegawa.saitama.jp +niiza.saitama.jp +ogano.saitama.jp +ogawa.saitama.jp +ogose.saitama.jp +okegawa.saitama.jp +omiya.saitama.jp +otaki.saitama.jp +ranzan.saitama.jp +ryokami.saitama.jp +saitama.saitama.jp +sakado.saitama.jp +satte.saitama.jp +sayama.saitama.jp +shiki.saitama.jp +shiraoka.saitama.jp +soka.saitama.jp +sugito.saitama.jp +toda.saitama.jp +tokigawa.saitama.jp +tokorozawa.saitama.jp +tsurugashima.saitama.jp +urawa.saitama.jp +warabi.saitama.jp +yashio.saitama.jp +yokoze.saitama.jp +yono.saitama.jp +yorii.saitama.jp +yoshida.saitama.jp +yoshikawa.saitama.jp +yoshimi.saitama.jp +aisho.shiga.jp +gamo.shiga.jp +higashiomi.shiga.jp +hikone.shiga.jp +koka.shiga.jp +konan.shiga.jp +kosei.shiga.jp +koto.shiga.jp +kusatsu.shiga.jp +maibara.shiga.jp +moriyama.shiga.jp +nagahama.shiga.jp +nishiazai.shiga.jp +notogawa.shiga.jp +omihachiman.shiga.jp +otsu.shiga.jp +ritto.shiga.jp +ryuoh.shiga.jp +takashima.shiga.jp +takatsuki.shiga.jp +torahime.shiga.jp +toyosato.shiga.jp +yasu.shiga.jp +akagi.shimane.jp +ama.shimane.jp +gotsu.shimane.jp +hamada.shimane.jp +higashiizumo.shimane.jp +hikawa.shimane.jp +hikimi.shimane.jp +izumo.shimane.jp +kakinoki.shimane.jp +masuda.shimane.jp +matsue.shimane.jp +misato.shimane.jp +nishinoshima.shimane.jp +ohda.shimane.jp +okinoshima.shimane.jp +okuizumo.shimane.jp +shimane.shimane.jp +tamayu.shimane.jp +tsuwano.shimane.jp +unnan.shimane.jp +yakumo.shimane.jp +yasugi.shimane.jp +yatsuka.shimane.jp +arai.shizuoka.jp +atami.shizuoka.jp +fuji.shizuoka.jp +fujieda.shizuoka.jp +fujikawa.shizuoka.jp +fujinomiya.shizuoka.jp +fukuroi.shizuoka.jp +gotemba.shizuoka.jp +haibara.shizuoka.jp +hamamatsu.shizuoka.jp +higashiizu.shizuoka.jp +ito.shizuoka.jp +iwata.shizuoka.jp +izu.shizuoka.jp +izunokuni.shizuoka.jp +kakegawa.shizuoka.jp +kannami.shizuoka.jp +kawanehon.shizuoka.jp +kawazu.shizuoka.jp +kikugawa.shizuoka.jp +kosai.shizuoka.jp +makinohara.shizuoka.jp +matsuzaki.shizuoka.jp +minamiizu.shizuoka.jp +mishima.shizuoka.jp +morimachi.shizuoka.jp +nishiizu.shizuoka.jp +numazu.shizuoka.jp +omaezaki.shizuoka.jp +shimada.shizuoka.jp +shimizu.shizuoka.jp +shimoda.shizuoka.jp +shizuoka.shizuoka.jp +susono.shizuoka.jp +yaizu.shizuoka.jp +yoshida.shizuoka.jp +ashikaga.tochigi.jp +bato.tochigi.jp +haga.tochigi.jp +ichikai.tochigi.jp +iwafune.tochigi.jp +kaminokawa.tochigi.jp +kanuma.tochigi.jp +karasuyama.tochigi.jp +kuroiso.tochigi.jp +mashiko.tochigi.jp +mibu.tochigi.jp +moka.tochigi.jp +motegi.tochigi.jp +nasu.tochigi.jp +nasushiobara.tochigi.jp +nikko.tochigi.jp +nishikata.tochigi.jp +nogi.tochigi.jp +ohira.tochigi.jp +ohtawara.tochigi.jp +oyama.tochigi.jp +sakura.tochigi.jp +sano.tochigi.jp +shimotsuke.tochigi.jp +shioya.tochigi.jp +takanezawa.tochigi.jp +tochigi.tochigi.jp +tsuga.tochigi.jp +ujiie.tochigi.jp +utsunomiya.tochigi.jp +yaita.tochigi.jp +aizumi.tokushima.jp +anan.tokushima.jp +ichiba.tokushima.jp +itano.tokushima.jp +kainan.tokushima.jp +komatsushima.tokushima.jp +matsushige.tokushima.jp +mima.tokushima.jp +minami.tokushima.jp +miyoshi.tokushima.jp +mugi.tokushima.jp +nakagawa.tokushima.jp +naruto.tokushima.jp +sanagochi.tokushima.jp +shishikui.tokushima.jp +tokushima.tokushima.jp +wajiki.tokushima.jp +adachi.tokyo.jp +akiruno.tokyo.jp +akishima.tokyo.jp +aogashima.tokyo.jp +arakawa.tokyo.jp +bunkyo.tokyo.jp +chiyoda.tokyo.jp +chofu.tokyo.jp +chuo.tokyo.jp +edogawa.tokyo.jp +fuchu.tokyo.jp +fussa.tokyo.jp +hachijo.tokyo.jp +hachioji.tokyo.jp +hamura.tokyo.jp +higashikurume.tokyo.jp +higashimurayama.tokyo.jp +higashiyamato.tokyo.jp +hino.tokyo.jp +hinode.tokyo.jp +hinohara.tokyo.jp +inagi.tokyo.jp +itabashi.tokyo.jp +katsushika.tokyo.jp +kita.tokyo.jp +kiyose.tokyo.jp +kodaira.tokyo.jp +koganei.tokyo.jp +kokubunji.tokyo.jp +komae.tokyo.jp +koto.tokyo.jp +kouzushima.tokyo.jp +kunitachi.tokyo.jp +machida.tokyo.jp +meguro.tokyo.jp +minato.tokyo.jp +mitaka.tokyo.jp +mizuho.tokyo.jp +musashimurayama.tokyo.jp +musashino.tokyo.jp +nakano.tokyo.jp +nerima.tokyo.jp +ogasawara.tokyo.jp +okutama.tokyo.jp +ome.tokyo.jp +oshima.tokyo.jp +ota.tokyo.jp +setagaya.tokyo.jp +shibuya.tokyo.jp +shinagawa.tokyo.jp +shinjuku.tokyo.jp +suginami.tokyo.jp +sumida.tokyo.jp +tachikawa.tokyo.jp +taito.tokyo.jp +tama.tokyo.jp +toshima.tokyo.jp +chizu.tottori.jp +hino.tottori.jp +kawahara.tottori.jp +koge.tottori.jp +kotoura.tottori.jp +misasa.tottori.jp +nanbu.tottori.jp +nichinan.tottori.jp +sakaiminato.tottori.jp +tottori.tottori.jp +wakasa.tottori.jp +yazu.tottori.jp +yonago.tottori.jp +asahi.toyama.jp +fuchu.toyama.jp +fukumitsu.toyama.jp +funahashi.toyama.jp +himi.toyama.jp +imizu.toyama.jp +inami.toyama.jp +johana.toyama.jp +kamiichi.toyama.jp +kurobe.toyama.jp +nakaniikawa.toyama.jp +namerikawa.toyama.jp +nanto.toyama.jp +nyuzen.toyama.jp +oyabe.toyama.jp +taira.toyama.jp +takaoka.toyama.jp +tateyama.toyama.jp +toga.toyama.jp +tonami.toyama.jp +toyama.toyama.jp +unazuki.toyama.jp +uozu.toyama.jp +yamada.toyama.jp +arida.wakayama.jp +aridagawa.wakayama.jp +gobo.wakayama.jp +hashimoto.wakayama.jp +hidaka.wakayama.jp +hirogawa.wakayama.jp +inami.wakayama.jp +iwade.wakayama.jp +kainan.wakayama.jp +kamitonda.wakayama.jp +katsuragi.wakayama.jp +kimino.wakayama.jp +kinokawa.wakayama.jp +kitayama.wakayama.jp +koya.wakayama.jp +koza.wakayama.jp +kozagawa.wakayama.jp +kudoyama.wakayama.jp +kushimoto.wakayama.jp +mihama.wakayama.jp +misato.wakayama.jp +nachikatsuura.wakayama.jp +shingu.wakayama.jp +shirahama.wakayama.jp +taiji.wakayama.jp +tanabe.wakayama.jp +wakayama.wakayama.jp +yuasa.wakayama.jp +yura.wakayama.jp +asahi.yamagata.jp +funagata.yamagata.jp +higashine.yamagata.jp +iide.yamagata.jp +kahoku.yamagata.jp +kaminoyama.yamagata.jp +kaneyama.yamagata.jp +kawanishi.yamagata.jp +mamurogawa.yamagata.jp +mikawa.yamagata.jp +murayama.yamagata.jp +nagai.yamagata.jp +nakayama.yamagata.jp +nanyo.yamagata.jp +nishikawa.yamagata.jp +obanazawa.yamagata.jp +oe.yamagata.jp +oguni.yamagata.jp +ohkura.yamagata.jp +oishida.yamagata.jp +sagae.yamagata.jp +sakata.yamagata.jp +sakegawa.yamagata.jp +shinjo.yamagata.jp +shirataka.yamagata.jp +shonai.yamagata.jp +takahata.yamagata.jp +tendo.yamagata.jp +tozawa.yamagata.jp +tsuruoka.yamagata.jp +yamagata.yamagata.jp +yamanobe.yamagata.jp +yonezawa.yamagata.jp +yuza.yamagata.jp +abu.yamaguchi.jp +hagi.yamaguchi.jp +hikari.yamaguchi.jp +hofu.yamaguchi.jp +iwakuni.yamaguchi.jp +kudamatsu.yamaguchi.jp +mitou.yamaguchi.jp +nagato.yamaguchi.jp +oshima.yamaguchi.jp +shimonoseki.yamaguchi.jp +shunan.yamaguchi.jp +tabuse.yamaguchi.jp +tokuyama.yamaguchi.jp +toyota.yamaguchi.jp +ube.yamaguchi.jp +yuu.yamaguchi.jp +chuo.yamanashi.jp +doshi.yamanashi.jp +fuefuki.yamanashi.jp +fujikawa.yamanashi.jp +fujikawaguchiko.yamanashi.jp +fujiyoshida.yamanashi.jp +hayakawa.yamanashi.jp +hokuto.yamanashi.jp +ichikawamisato.yamanashi.jp +kai.yamanashi.jp +kofu.yamanashi.jp +koshu.yamanashi.jp +kosuge.yamanashi.jp +minami-alps.yamanashi.jp +minobu.yamanashi.jp +nakamichi.yamanashi.jp +nanbu.yamanashi.jp +narusawa.yamanashi.jp +nirasaki.yamanashi.jp +nishikatsura.yamanashi.jp +oshino.yamanashi.jp +otsuki.yamanashi.jp +showa.yamanashi.jp +tabayama.yamanashi.jp +tsuru.yamanashi.jp +uenohara.yamanashi.jp +yamanakako.yamanashi.jp +yamanashi.yamanashi.jp + +// ke : http://www.kenic.or.ke/index.php/en/ke-domains/ke-domains +ke +ac.ke +co.ke +go.ke +info.ke +me.ke +mobi.ke +ne.ke +or.ke +sc.ke + +// kg : http://www.domain.kg/dmn_n.html +kg +org.kg +net.kg +com.kg +edu.kg +gov.kg +mil.kg + +// kh : http://www.mptc.gov.kh/dns_registration.htm +*.kh + +// ki : http://www.ki/dns/index.html +ki +edu.ki +biz.ki +net.ki +org.ki +gov.ki +info.ki +com.ki + +// km : https://en.wikipedia.org/wiki/.km +// http://www.domaine.km/documents/charte.doc +km +org.km +nom.km +gov.km +prd.km +tm.km +edu.km +mil.km +ass.km +com.km +// These are only mentioned as proposed suggestions at domaine.km, but +// https://en.wikipedia.org/wiki/.km says they're available for registration: +coop.km +asso.km +presse.km +medecin.km +notaires.km +pharmaciens.km +veterinaire.km +gouv.km + +// kn : https://en.wikipedia.org/wiki/.kn +// http://www.dot.kn/domainRules.html +kn +net.kn +org.kn +edu.kn +gov.kn + +// kp : http://www.kcce.kp/en_index.php +kp +com.kp +edu.kp +gov.kp +org.kp +rep.kp +tra.kp + +// kr : https://en.wikipedia.org/wiki/.kr +// see also: http://domain.nida.or.kr/eng/registration.jsp +kr +ac.kr +co.kr +es.kr +go.kr +hs.kr +kg.kr +mil.kr +ms.kr +ne.kr +or.kr +pe.kr +re.kr +sc.kr +// kr geographical names +busan.kr +chungbuk.kr +chungnam.kr +daegu.kr +daejeon.kr +gangwon.kr +gwangju.kr +gyeongbuk.kr +gyeonggi.kr +gyeongnam.kr +incheon.kr +jeju.kr +jeonbuk.kr +jeonnam.kr +seoul.kr +ulsan.kr + +// kw : https://www.nic.kw/policies/ +// Confirmed by registry +kw +com.kw +edu.kw +emb.kw +gov.kw +ind.kw +net.kw +org.kw + +// ky : http://www.icta.ky/da_ky_reg_dom.php +// Confirmed by registry 2008-06-17 +ky +edu.ky +gov.ky +com.ky +org.ky +net.ky + +// kz : https://en.wikipedia.org/wiki/.kz +// see also: http://www.nic.kz/rules/index.jsp +kz +org.kz +edu.kz +net.kz +gov.kz +mil.kz +com.kz + +// la : https://en.wikipedia.org/wiki/.la +// Submitted by registry +la +int.la +net.la +info.la +edu.la +gov.la +per.la +com.la +org.la + +// lb : https://en.wikipedia.org/wiki/.lb +// Submitted by registry +lb +com.lb +edu.lb +gov.lb +net.lb +org.lb + +// lc : https://en.wikipedia.org/wiki/.lc +// see also: http://www.nic.lc/rules.htm +lc +com.lc +net.lc +co.lc +org.lc +edu.lc +gov.lc + +// li : https://en.wikipedia.org/wiki/.li +li + +// lk : https://www.nic.lk/index.php/domain-registration/lk-domain-naming-structure +lk +gov.lk +sch.lk +net.lk +int.lk +com.lk +org.lk +edu.lk +ngo.lk +soc.lk +web.lk +ltd.lk +assn.lk +grp.lk +hotel.lk +ac.lk + +// lr : http://psg.com/dns/lr/lr.txt +// Submitted by registry +lr +com.lr +edu.lr +gov.lr +org.lr +net.lr + +// ls : http://www.nic.ls/ +// Confirmed by registry +ls +ac.ls +biz.ls +co.ls +edu.ls +gov.ls +info.ls +net.ls +org.ls +sc.ls + +// lt : https://en.wikipedia.org/wiki/.lt +lt +// gov.lt : http://www.gov.lt/index_en.php +gov.lt + +// lu : http://www.dns.lu/en/ +lu + +// lv : http://www.nic.lv/DNS/En/generic.php +lv +com.lv +edu.lv +gov.lv +org.lv +mil.lv +id.lv +net.lv +asn.lv +conf.lv + +// ly : http://www.nic.ly/regulations.php +ly +com.ly +net.ly +gov.ly +plc.ly +edu.ly +sch.ly +med.ly +org.ly +id.ly + +// ma : https://en.wikipedia.org/wiki/.ma +// http://www.anrt.ma/fr/admin/download/upload/file_fr782.pdf +ma +co.ma +net.ma +gov.ma +org.ma +ac.ma +press.ma + +// mc : http://www.nic.mc/ +mc +tm.mc +asso.mc + +// md : https://en.wikipedia.org/wiki/.md +md + +// me : https://en.wikipedia.org/wiki/.me +me +co.me +net.me +org.me +edu.me +ac.me +gov.me +its.me +priv.me + +// mg : http://nic.mg/nicmg/?page_id=39 +mg +org.mg +nom.mg +gov.mg +prd.mg +tm.mg +edu.mg +mil.mg +com.mg +co.mg + +// mh : https://en.wikipedia.org/wiki/.mh +mh + +// mil : https://en.wikipedia.org/wiki/.mil +mil + +// mk : https://en.wikipedia.org/wiki/.mk +// see also: http://dns.marnet.net.mk/postapka.php +mk +com.mk +org.mk +net.mk +edu.mk +gov.mk +inf.mk +name.mk + +// ml : http://www.gobin.info/domainname/ml-template.doc +// see also: https://en.wikipedia.org/wiki/.ml +ml +com.ml +edu.ml +gouv.ml +gov.ml +net.ml +org.ml +presse.ml + +// mm : https://en.wikipedia.org/wiki/.mm +*.mm + +// mn : https://en.wikipedia.org/wiki/.mn +mn +gov.mn +edu.mn +org.mn + +// mo : http://www.monic.net.mo/ +mo +com.mo +net.mo +org.mo +edu.mo +gov.mo + +// mobi : https://en.wikipedia.org/wiki/.mobi +mobi + +// mp : http://www.dot.mp/ +// Confirmed by registry 2008-06-17 +mp + +// mq : https://en.wikipedia.org/wiki/.mq +mq + +// mr : https://en.wikipedia.org/wiki/.mr +mr +gov.mr + +// ms : http://www.nic.ms/pdf/MS_Domain_Name_Rules.pdf +ms +com.ms +edu.ms +gov.ms +net.ms +org.ms + +// mt : https://www.nic.org.mt/go/policy +// Submitted by registry +mt +com.mt +edu.mt +net.mt +org.mt + +// mu : https://en.wikipedia.org/wiki/.mu +mu +com.mu +net.mu +org.mu +gov.mu +ac.mu +co.mu +or.mu + +// museum : http://about.museum/naming/ +// http://index.museum/ +museum +academy.museum +agriculture.museum +air.museum +airguard.museum +alabama.museum +alaska.museum +amber.museum +ambulance.museum +american.museum +americana.museum +americanantiques.museum +americanart.museum +amsterdam.museum +and.museum +annefrank.museum +anthro.museum +anthropology.museum +antiques.museum +aquarium.museum +arboretum.museum +archaeological.museum +archaeology.museum +architecture.museum +art.museum +artanddesign.museum +artcenter.museum +artdeco.museum +arteducation.museum +artgallery.museum +arts.museum +artsandcrafts.museum +asmatart.museum +assassination.museum +assisi.museum +association.museum +astronomy.museum +atlanta.museum +austin.museum +australia.museum +automotive.museum +aviation.museum +axis.museum +badajoz.museum +baghdad.museum +bahn.museum +bale.museum +baltimore.museum +barcelona.museum +baseball.museum +basel.museum +baths.museum +bauern.museum +beauxarts.museum +beeldengeluid.museum +bellevue.museum +bergbau.museum +berkeley.museum +berlin.museum +bern.museum +bible.museum +bilbao.museum +bill.museum +birdart.museum +birthplace.museum +bonn.museum +boston.museum +botanical.museum +botanicalgarden.museum +botanicgarden.museum +botany.museum +brandywinevalley.museum +brasil.museum +bristol.museum +british.museum +britishcolumbia.museum +broadcast.museum +brunel.museum +brussel.museum +brussels.museum +bruxelles.museum +building.museum +burghof.museum +bus.museum +bushey.museum +cadaques.museum +california.museum +cambridge.museum +can.museum +canada.museum +capebreton.museum +carrier.museum +cartoonart.museum +casadelamoneda.museum +castle.museum +castres.museum +celtic.museum +center.museum +chattanooga.museum +cheltenham.museum +chesapeakebay.museum +chicago.museum +children.museum +childrens.museum +childrensgarden.museum +chiropractic.museum +chocolate.museum +christiansburg.museum +cincinnati.museum +cinema.museum +circus.museum +civilisation.museum +civilization.museum +civilwar.museum +clinton.museum +clock.museum +coal.museum +coastaldefence.museum +cody.museum +coldwar.museum +collection.museum +colonialwilliamsburg.museum +coloradoplateau.museum +columbia.museum +columbus.museum +communication.museum +communications.museum +community.museum +computer.museum +computerhistory.museum +comunicações.museum +contemporary.museum +contemporaryart.museum +convent.museum +copenhagen.museum +corporation.museum +correios-e-telecomunicações.museum +corvette.museum +costume.museum +countryestate.museum +county.museum +crafts.museum +cranbrook.museum +creation.museum +cultural.museum +culturalcenter.museum +culture.museum +cyber.museum +cymru.museum +dali.museum +dallas.museum +database.museum +ddr.museum +decorativearts.museum +delaware.museum +delmenhorst.museum +denmark.museum +depot.museum +design.museum +detroit.museum +dinosaur.museum +discovery.museum +dolls.museum +donostia.museum +durham.museum +eastafrica.museum +eastcoast.museum +education.museum +educational.museum +egyptian.museum +eisenbahn.museum +elburg.museum +elvendrell.museum +embroidery.museum +encyclopedic.museum +england.museum +entomology.museum +environment.museum +environmentalconservation.museum +epilepsy.museum +essex.museum +estate.museum +ethnology.museum +exeter.museum +exhibition.museum +family.museum +farm.museum +farmequipment.museum +farmers.museum +farmstead.museum +field.museum +figueres.museum +filatelia.museum +film.museum +fineart.museum +finearts.museum +finland.museum +flanders.museum +florida.museum +force.museum +fortmissoula.museum +fortworth.museum +foundation.museum +francaise.museum +frankfurt.museum +franziskaner.museum +freemasonry.museum +freiburg.museum +fribourg.museum +frog.museum +fundacio.museum +furniture.museum +gallery.museum +garden.museum +gateway.museum +geelvinck.museum +gemological.museum +geology.museum +georgia.museum +giessen.museum +glas.museum +glass.museum +gorge.museum +grandrapids.museum +graz.museum +guernsey.museum +halloffame.museum +hamburg.museum +handson.museum +harvestcelebration.museum +hawaii.museum +health.museum +heimatunduhren.museum +hellas.museum +helsinki.museum +hembygdsforbund.museum +heritage.museum +histoire.museum +historical.museum +historicalsociety.museum +historichouses.museum +historisch.museum +historisches.museum +history.museum +historyofscience.museum +horology.museum +house.museum +humanities.museum +illustration.museum +imageandsound.museum +indian.museum +indiana.museum +indianapolis.museum +indianmarket.museum +intelligence.museum +interactive.museum +iraq.museum +iron.museum +isleofman.museum +jamison.museum +jefferson.museum +jerusalem.museum +jewelry.museum +jewish.museum +jewishart.museum +jfk.museum +journalism.museum +judaica.museum +judygarland.museum +juedisches.museum +juif.museum +karate.museum +karikatur.museum +kids.museum +koebenhavn.museum +koeln.museum +kunst.museum +kunstsammlung.museum +kunstunddesign.museum +labor.museum +labour.museum +lajolla.museum +lancashire.museum +landes.museum +lans.museum +läns.museum +larsson.museum +lewismiller.museum +lincoln.museum +linz.museum +living.museum +livinghistory.museum +localhistory.museum +london.museum +losangeles.museum +louvre.museum +loyalist.museum +lucerne.museum +luxembourg.museum +luzern.museum +mad.museum +madrid.museum +mallorca.museum +manchester.museum +mansion.museum +mansions.museum +manx.museum +marburg.museum +maritime.museum +maritimo.museum +maryland.museum +marylhurst.museum +media.museum +medical.museum +medizinhistorisches.museum +meeres.museum +memorial.museum +mesaverde.museum +michigan.museum +midatlantic.museum +military.museum +mill.museum +miners.museum +mining.museum +minnesota.museum +missile.museum +missoula.museum +modern.museum +moma.museum +money.museum +monmouth.museum +monticello.museum +montreal.museum +moscow.museum +motorcycle.museum +muenchen.museum +muenster.museum +mulhouse.museum +muncie.museum +museet.museum +museumcenter.museum +museumvereniging.museum +music.museum +national.museum +nationalfirearms.museum +nationalheritage.museum +nativeamerican.museum +naturalhistory.museum +naturalhistorymuseum.museum +naturalsciences.museum +nature.museum +naturhistorisches.museum +natuurwetenschappen.museum +naumburg.museum +naval.museum +nebraska.museum +neues.museum +newhampshire.museum +newjersey.museum +newmexico.museum +newport.museum +newspaper.museum +newyork.museum +niepce.museum +norfolk.museum +north.museum +nrw.museum +nyc.museum +nyny.museum +oceanographic.museum +oceanographique.museum +omaha.museum +online.museum +ontario.museum +openair.museum +oregon.museum +oregontrail.museum +otago.museum +oxford.museum +pacific.museum +paderborn.museum +palace.museum +paleo.museum +palmsprings.museum +panama.museum +paris.museum +pasadena.museum +pharmacy.museum +philadelphia.museum +philadelphiaarea.museum +philately.museum +phoenix.museum +photography.museum +pilots.museum +pittsburgh.museum +planetarium.museum +plantation.museum +plants.museum +plaza.museum +portal.museum +portland.museum +portlligat.museum +posts-and-telecommunications.museum +preservation.museum +presidio.museum +press.museum +project.museum +public.museum +pubol.museum +quebec.museum +railroad.museum +railway.museum +research.museum +resistance.museum +riodejaneiro.museum +rochester.museum +rockart.museum +roma.museum +russia.museum +saintlouis.museum +salem.museum +salvadordali.museum +salzburg.museum +sandiego.museum +sanfrancisco.museum +santabarbara.museum +santacruz.museum +santafe.museum +saskatchewan.museum +satx.museum +savannahga.museum +schlesisches.museum +schoenbrunn.museum +schokoladen.museum +school.museum +schweiz.museum +science.museum +scienceandhistory.museum +scienceandindustry.museum +sciencecenter.museum +sciencecenters.museum +science-fiction.museum +sciencehistory.museum +sciences.museum +sciencesnaturelles.museum +scotland.museum +seaport.museum +settlement.museum +settlers.museum +shell.museum +sherbrooke.museum +sibenik.museum +silk.museum +ski.museum +skole.museum +society.museum +sologne.museum +soundandvision.museum +southcarolina.museum +southwest.museum +space.museum +spy.museum +square.museum +stadt.museum +stalbans.museum +starnberg.museum +state.museum +stateofdelaware.museum +station.museum +steam.museum +steiermark.museum +stjohn.museum +stockholm.museum +stpetersburg.museum +stuttgart.museum +suisse.museum +surgeonshall.museum +surrey.museum +svizzera.museum +sweden.museum +sydney.museum +tank.museum +tcm.museum +technology.museum +telekommunikation.museum +television.museum +texas.museum +textile.museum +theater.museum +time.museum +timekeeping.museum +topology.museum +torino.museum +touch.museum +town.museum +transport.museum +tree.museum +trolley.museum +trust.museum +trustee.museum +uhren.museum +ulm.museum +undersea.museum +university.museum +usa.museum +usantiques.museum +usarts.museum +uscountryestate.museum +usculture.museum +usdecorativearts.museum +usgarden.museum +ushistory.museum +ushuaia.museum +uslivinghistory.museum +utah.museum +uvic.museum +valley.museum +vantaa.museum +versailles.museum +viking.museum +village.museum +virginia.museum +virtual.museum +virtuel.museum +vlaanderen.museum +volkenkunde.museum +wales.museum +wallonie.museum +war.museum +washingtondc.museum +watchandclock.museum +watch-and-clock.museum +western.museum +westfalen.museum +whaling.museum +wildlife.museum +williamsburg.museum +windmill.museum +workshop.museum +york.museum +yorkshire.museum +yosemite.museum +youth.museum +zoological.museum +zoology.museum +ירושלים.museum +иком.museum + +// mv : https://en.wikipedia.org/wiki/.mv +// "mv" included because, contra Wikipedia, google.mv exists. +mv +aero.mv +biz.mv +com.mv +coop.mv +edu.mv +gov.mv +info.mv +int.mv +mil.mv +museum.mv +name.mv +net.mv +org.mv +pro.mv + +// mw : http://www.registrar.mw/ +mw +ac.mw +biz.mw +co.mw +com.mw +coop.mw +edu.mw +gov.mw +int.mw +museum.mw +net.mw +org.mw + +// mx : http://www.nic.mx/ +// Submitted by registry +mx +com.mx +org.mx +gob.mx +edu.mx +net.mx + +// my : http://www.mynic.net.my/ +my +com.my +net.my +org.my +gov.my +edu.my +mil.my +name.my + +// mz : http://www.uem.mz/ +// Submitted by registry +mz +ac.mz +adv.mz +co.mz +edu.mz +gov.mz +mil.mz +net.mz +org.mz + +// na : http://www.na-nic.com.na/ +// http://www.info.na/domain/ +na +info.na +pro.na +name.na +school.na +or.na +dr.na +us.na +mx.na +ca.na +in.na +cc.na +tv.na +ws.na +mobi.na +co.na +com.na +org.na + +// name : has 2nd-level tlds, but there's no list of them +name + +// nc : http://www.cctld.nc/ +nc +asso.nc +nom.nc + +// ne : https://en.wikipedia.org/wiki/.ne +ne + +// net : https://en.wikipedia.org/wiki/.net +net + +// nf : https://en.wikipedia.org/wiki/.nf +nf +com.nf +net.nf +per.nf +rec.nf +web.nf +arts.nf +firm.nf +info.nf +other.nf +store.nf + +// ng : http://www.nira.org.ng/index.php/join-us/register-ng-domain/189-nira-slds +ng +com.ng +edu.ng +gov.ng +i.ng +mil.ng +mobi.ng +name.ng +net.ng +org.ng +sch.ng + +// ni : http://www.nic.ni/ +ni +ac.ni +biz.ni +co.ni +com.ni +edu.ni +gob.ni +in.ni +info.ni +int.ni +mil.ni +net.ni +nom.ni +org.ni +web.ni + +// nl : https://en.wikipedia.org/wiki/.nl +// https://www.sidn.nl/ +// ccTLD for the Netherlands +nl + +// no : https://www.norid.no/en/om-domenenavn/regelverk-for-no/ +// Norid geographical second level domains : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-b/ +// Norid category second level domains : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-c/ +// Norid category second-level domains managed by parties other than Norid : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-d/ +// RSS feed: https://teknisk.norid.no/en/feed/ +no +// Norid category second level domains : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-c/ +fhs.no +vgs.no +fylkesbibl.no +folkebibl.no +museum.no +idrett.no +priv.no +// Norid category second-level domains managed by parties other than Norid : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-d/ +mil.no +stat.no +dep.no +kommune.no +herad.no +// Norid geographical second level domains : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-b/ +// counties +aa.no +ah.no +bu.no +fm.no +hl.no +hm.no +jan-mayen.no +mr.no +nl.no +nt.no +of.no +ol.no +oslo.no +rl.no +sf.no +st.no +svalbard.no +tm.no +tr.no +va.no +vf.no +// primary and lower secondary schools per county +gs.aa.no +gs.ah.no +gs.bu.no +gs.fm.no +gs.hl.no +gs.hm.no +gs.jan-mayen.no +gs.mr.no +gs.nl.no +gs.nt.no +gs.of.no +gs.ol.no +gs.oslo.no +gs.rl.no +gs.sf.no +gs.st.no +gs.svalbard.no +gs.tm.no +gs.tr.no +gs.va.no +gs.vf.no +// cities +akrehamn.no +åkrehamn.no +algard.no +ålgård.no +arna.no +brumunddal.no +bryne.no +bronnoysund.no +brønnøysund.no +drobak.no +drøbak.no +egersund.no +fetsund.no +floro.no +florø.no +fredrikstad.no +hokksund.no +honefoss.no +hønefoss.no +jessheim.no +jorpeland.no +jørpeland.no +kirkenes.no +kopervik.no +krokstadelva.no +langevag.no +langevåg.no +leirvik.no +mjondalen.no +mjøndalen.no +mo-i-rana.no +mosjoen.no +mosjøen.no +nesoddtangen.no +orkanger.no +osoyro.no +osøyro.no +raholt.no +råholt.no +sandnessjoen.no +sandnessjøen.no +skedsmokorset.no +slattum.no +spjelkavik.no +stathelle.no +stavern.no +stjordalshalsen.no +stjørdalshalsen.no +tananger.no +tranby.no +vossevangen.no +// communities +afjord.no +åfjord.no +agdenes.no +al.no +ål.no +alesund.no +ålesund.no +alstahaug.no +alta.no +áltá.no +alaheadju.no +álaheadju.no +alvdal.no +amli.no +åmli.no +amot.no +åmot.no +andebu.no +andoy.no +andøy.no +andasuolo.no +ardal.no +årdal.no +aremark.no +arendal.no +ås.no +aseral.no +åseral.no +asker.no +askim.no +askvoll.no +askoy.no +askøy.no +asnes.no +åsnes.no +audnedaln.no +aukra.no +aure.no +aurland.no +aurskog-holand.no +aurskog-høland.no +austevoll.no +austrheim.no +averoy.no +averøy.no +balestrand.no +ballangen.no +balat.no +bálát.no +balsfjord.no +bahccavuotna.no +báhccavuotna.no +bamble.no +bardu.no +beardu.no +beiarn.no +bajddar.no +bájddar.no +baidar.no +báidár.no +berg.no +bergen.no +berlevag.no +berlevåg.no +bearalvahki.no +bearalváhki.no +bindal.no +birkenes.no +bjarkoy.no +bjarkøy.no +bjerkreim.no +bjugn.no +bodo.no +bodø.no +badaddja.no +bådåddjå.no +budejju.no +bokn.no +bremanger.no +bronnoy.no +brønnøy.no +bygland.no +bykle.no +barum.no +bærum.no +bo.telemark.no +bø.telemark.no +bo.nordland.no +bø.nordland.no +bievat.no +bievát.no +bomlo.no +bømlo.no +batsfjord.no +båtsfjord.no +bahcavuotna.no +báhcavuotna.no +dovre.no +drammen.no +drangedal.no +dyroy.no +dyrøy.no +donna.no +dønna.no +eid.no +eidfjord.no +eidsberg.no +eidskog.no +eidsvoll.no +eigersund.no +elverum.no +enebakk.no +engerdal.no +etne.no +etnedal.no +evenes.no +evenassi.no +evenášši.no +evje-og-hornnes.no +farsund.no +fauske.no +fuossko.no +fuoisku.no +fedje.no +fet.no +finnoy.no +finnøy.no +fitjar.no +fjaler.no +fjell.no +flakstad.no +flatanger.no +flekkefjord.no +flesberg.no +flora.no +fla.no +flå.no +folldal.no +forsand.no +fosnes.no +frei.no +frogn.no +froland.no +frosta.no +frana.no +fræna.no +froya.no +frøya.no +fusa.no +fyresdal.no +forde.no +førde.no +gamvik.no +gangaviika.no +gáŋgaviika.no +gaular.no +gausdal.no +gildeskal.no +gildeskål.no +giske.no +gjemnes.no +gjerdrum.no +gjerstad.no +gjesdal.no +gjovik.no +gjøvik.no +gloppen.no +gol.no +gran.no +grane.no +granvin.no +gratangen.no +grimstad.no +grong.no +kraanghke.no +kråanghke.no +grue.no +gulen.no +hadsel.no +halden.no +halsa.no +hamar.no +hamaroy.no +habmer.no +hábmer.no +hapmir.no +hápmir.no +hammerfest.no +hammarfeasta.no +hámmárfeasta.no +haram.no +hareid.no +harstad.no +hasvik.no +aknoluokta.no +ákŋoluokta.no +hattfjelldal.no +aarborte.no +haugesund.no +hemne.no +hemnes.no +hemsedal.no +heroy.more-og-romsdal.no +herøy.møre-og-romsdal.no +heroy.nordland.no +herøy.nordland.no +hitra.no +hjartdal.no +hjelmeland.no +hobol.no +hobøl.no +hof.no +hol.no +hole.no +holmestrand.no +holtalen.no +holtålen.no +hornindal.no +horten.no +hurdal.no +hurum.no +hvaler.no +hyllestad.no +hagebostad.no +hægebostad.no +hoyanger.no +høyanger.no +hoylandet.no +høylandet.no +ha.no +hå.no +ibestad.no +inderoy.no +inderøy.no +iveland.no +jevnaker.no +jondal.no +jolster.no +jølster.no +karasjok.no +karasjohka.no +kárášjohka.no +karlsoy.no +galsa.no +gálsá.no +karmoy.no +karmøy.no +kautokeino.no +guovdageaidnu.no +klepp.no +klabu.no +klæbu.no +kongsberg.no +kongsvinger.no +kragero.no +kragerø.no +kristiansand.no +kristiansund.no +krodsherad.no +krødsherad.no +kvalsund.no +rahkkeravju.no +ráhkkerávju.no +kvam.no +kvinesdal.no +kvinnherad.no +kviteseid.no +kvitsoy.no +kvitsøy.no +kvafjord.no +kvæfjord.no +giehtavuoatna.no +kvanangen.no +kvænangen.no +navuotna.no +návuotna.no +kafjord.no +kåfjord.no +gaivuotna.no +gáivuotna.no +larvik.no +lavangen.no +lavagis.no +loabat.no +loabát.no +lebesby.no +davvesiida.no +leikanger.no +leirfjord.no +leka.no +leksvik.no +lenvik.no +leangaviika.no +leaŋgaviika.no +lesja.no +levanger.no +lier.no +lierne.no +lillehammer.no +lillesand.no +lindesnes.no +lindas.no +lindås.no +lom.no +loppa.no +lahppi.no +láhppi.no +lund.no +lunner.no +luroy.no +lurøy.no +luster.no +lyngdal.no +lyngen.no +ivgu.no +lardal.no +lerdal.no +lærdal.no +lodingen.no +lødingen.no +lorenskog.no +lørenskog.no +loten.no +løten.no +malvik.no +masoy.no +måsøy.no +muosat.no +muosát.no +mandal.no +marker.no +marnardal.no +masfjorden.no +meland.no +meldal.no +melhus.no +meloy.no +meløy.no +meraker.no +meråker.no +moareke.no +moåreke.no +midsund.no +midtre-gauldal.no +modalen.no +modum.no +molde.no +moskenes.no +moss.no +mosvik.no +malselv.no +målselv.no +malatvuopmi.no +málatvuopmi.no +namdalseid.no +aejrie.no +namsos.no +namsskogan.no +naamesjevuemie.no +nååmesjevuemie.no +laakesvuemie.no +nannestad.no +narvik.no +narviika.no +naustdal.no +nedre-eiker.no +nes.akershus.no +nes.buskerud.no +nesna.no +nesodden.no +nesseby.no +unjarga.no +unjárga.no +nesset.no +nissedal.no +nittedal.no +nord-aurdal.no +nord-fron.no +nord-odal.no +norddal.no +nordkapp.no +davvenjarga.no +davvenjárga.no +nordre-land.no +nordreisa.no +raisa.no +ráisa.no +nore-og-uvdal.no +notodden.no +naroy.no +nærøy.no +notteroy.no +nøtterøy.no +odda.no +oksnes.no +øksnes.no +oppdal.no +oppegard.no +oppegård.no +orkdal.no +orland.no +ørland.no +orskog.no +ørskog.no +orsta.no +ørsta.no +os.hedmark.no +os.hordaland.no +osen.no +osteroy.no +osterøy.no +ostre-toten.no +østre-toten.no +overhalla.no +ovre-eiker.no +øvre-eiker.no +oyer.no +øyer.no +oygarden.no +øygarden.no +oystre-slidre.no +øystre-slidre.no +porsanger.no +porsangu.no +porsáŋgu.no +porsgrunn.no +radoy.no +radøy.no +rakkestad.no +rana.no +ruovat.no +randaberg.no +rauma.no +rendalen.no +rennebu.no +rennesoy.no +rennesøy.no +rindal.no +ringebu.no +ringerike.no +ringsaker.no +rissa.no +risor.no +risør.no +roan.no +rollag.no +rygge.no +ralingen.no +rælingen.no +rodoy.no +rødøy.no +romskog.no +rømskog.no +roros.no +røros.no +rost.no +røst.no +royken.no +røyken.no +royrvik.no +røyrvik.no +rade.no +råde.no +salangen.no +siellak.no +saltdal.no +salat.no +sálát.no +sálat.no +samnanger.no +sande.more-og-romsdal.no +sande.møre-og-romsdal.no +sande.vestfold.no +sandefjord.no +sandnes.no +sandoy.no +sandøy.no +sarpsborg.no +sauda.no +sauherad.no +sel.no +selbu.no +selje.no +seljord.no +sigdal.no +siljan.no +sirdal.no +skaun.no +skedsmo.no +ski.no +skien.no +skiptvet.no +skjervoy.no +skjervøy.no +skierva.no +skiervá.no +skjak.no +skjåk.no +skodje.no +skanland.no +skånland.no +skanit.no +skánit.no +smola.no +smøla.no +snillfjord.no +snasa.no +snåsa.no +snoasa.no +snaase.no +snåase.no +sogndal.no +sokndal.no +sola.no +solund.no +songdalen.no +sortland.no +spydeberg.no +stange.no +stavanger.no +steigen.no +steinkjer.no +stjordal.no +stjørdal.no +stokke.no +stor-elvdal.no +stord.no +stordal.no +storfjord.no +omasvuotna.no +strand.no +stranda.no +stryn.no +sula.no +suldal.no +sund.no +sunndal.no +surnadal.no +sveio.no +svelvik.no +sykkylven.no +sogne.no +søgne.no +somna.no +sømna.no +sondre-land.no +søndre-land.no +sor-aurdal.no +sør-aurdal.no +sor-fron.no +sør-fron.no +sor-odal.no +sør-odal.no +sor-varanger.no +sør-varanger.no +matta-varjjat.no +mátta-várjjat.no +sorfold.no +sørfold.no +sorreisa.no +sørreisa.no +sorum.no +sørum.no +tana.no +deatnu.no +time.no +tingvoll.no +tinn.no +tjeldsund.no +dielddanuorri.no +tjome.no +tjøme.no +tokke.no +tolga.no +torsken.no +tranoy.no +tranøy.no +tromso.no +tromsø.no +tromsa.no +romsa.no +trondheim.no +troandin.no +trysil.no +trana.no +træna.no +trogstad.no +trøgstad.no +tvedestrand.no +tydal.no +tynset.no +tysfjord.no +divtasvuodna.no +divttasvuotna.no +tysnes.no +tysvar.no +tysvær.no +tonsberg.no +tønsberg.no +ullensaker.no +ullensvang.no +ulvik.no +utsira.no +vadso.no +vadsø.no +cahcesuolo.no +čáhcesuolo.no +vaksdal.no +valle.no +vang.no +vanylven.no +vardo.no +vardø.no +varggat.no +várggát.no +vefsn.no +vaapste.no +vega.no +vegarshei.no +vegårshei.no +vennesla.no +verdal.no +verran.no +vestby.no +vestnes.no +vestre-slidre.no +vestre-toten.no +vestvagoy.no +vestvågøy.no +vevelstad.no +vik.no +vikna.no +vindafjord.no +volda.no +voss.no +varoy.no +værøy.no +vagan.no +vågan.no +voagat.no +vagsoy.no +vågsøy.no +vaga.no +vågå.no +valer.ostfold.no +våler.østfold.no +valer.hedmark.no +våler.hedmark.no + +// np : http://www.mos.com.np/register.html +*.np + +// nr : http://cenpac.net.nr/dns/index.html +// Submitted by registry +nr +biz.nr +info.nr +gov.nr +edu.nr +org.nr +net.nr +com.nr + +// nu : https://en.wikipedia.org/wiki/.nu +nu + +// nz : https://en.wikipedia.org/wiki/.nz +// Submitted by registry +nz +ac.nz +co.nz +cri.nz +geek.nz +gen.nz +govt.nz +health.nz +iwi.nz +kiwi.nz +maori.nz +mil.nz +māori.nz +net.nz +org.nz +parliament.nz +school.nz + +// om : https://en.wikipedia.org/wiki/.om +om +co.om +com.om +edu.om +gov.om +med.om +museum.om +net.om +org.om +pro.om + +// onion : https://tools.ietf.org/html/rfc7686 +onion + +// org : https://en.wikipedia.org/wiki/.org +org + +// pa : http://www.nic.pa/ +// Some additional second level "domains" resolve directly as hostnames, such as +// pannet.pa, so we add a rule for "pa". +pa +ac.pa +gob.pa +com.pa +org.pa +sld.pa +edu.pa +net.pa +ing.pa +abo.pa +med.pa +nom.pa + +// pe : https://www.nic.pe/InformeFinalComision.pdf +pe +edu.pe +gob.pe +nom.pe +mil.pe +org.pe +com.pe +net.pe + +// pf : http://www.gobin.info/domainname/formulaire-pf.pdf +pf +com.pf +org.pf +edu.pf + +// pg : https://en.wikipedia.org/wiki/.pg +*.pg + +// ph : http://www.domains.ph/FAQ2.asp +// Submitted by registry +ph +com.ph +net.ph +org.ph +gov.ph +edu.ph +ngo.ph +mil.ph +i.ph + +// pk : http://pk5.pknic.net.pk/pk5/msgNamepk.PK +pk +com.pk +net.pk +edu.pk +org.pk +fam.pk +biz.pk +web.pk +gov.pk +gob.pk +gok.pk +gon.pk +gop.pk +gos.pk +info.pk + +// pl http://www.dns.pl/english/index.html +// Submitted by registry +pl +com.pl +net.pl +org.pl +// pl functional domains (http://www.dns.pl/english/index.html) +aid.pl +agro.pl +atm.pl +auto.pl +biz.pl +edu.pl +gmina.pl +gsm.pl +info.pl +mail.pl +miasta.pl +media.pl +mil.pl +nieruchomosci.pl +nom.pl +pc.pl +powiat.pl +priv.pl +realestate.pl +rel.pl +sex.pl +shop.pl +sklep.pl +sos.pl +szkola.pl +targi.pl +tm.pl +tourism.pl +travel.pl +turystyka.pl +// Government domains +gov.pl +ap.gov.pl +ic.gov.pl +is.gov.pl +us.gov.pl +kmpsp.gov.pl +kppsp.gov.pl +kwpsp.gov.pl +psp.gov.pl +wskr.gov.pl +kwp.gov.pl +mw.gov.pl +ug.gov.pl +um.gov.pl +umig.gov.pl +ugim.gov.pl +upow.gov.pl +uw.gov.pl +starostwo.gov.pl +pa.gov.pl +po.gov.pl +psse.gov.pl +pup.gov.pl +rzgw.gov.pl +sa.gov.pl +so.gov.pl +sr.gov.pl +wsa.gov.pl +sko.gov.pl +uzs.gov.pl +wiih.gov.pl +winb.gov.pl +pinb.gov.pl +wios.gov.pl +witd.gov.pl +wzmiuw.gov.pl +piw.gov.pl +wiw.gov.pl +griw.gov.pl +wif.gov.pl +oum.gov.pl +sdn.gov.pl +zp.gov.pl +uppo.gov.pl +mup.gov.pl +wuoz.gov.pl +konsulat.gov.pl +oirm.gov.pl +// pl regional domains (http://www.dns.pl/english/index.html) +augustow.pl +babia-gora.pl +bedzin.pl +beskidy.pl +bialowieza.pl +bialystok.pl +bielawa.pl +bieszczady.pl +boleslawiec.pl +bydgoszcz.pl +bytom.pl +cieszyn.pl +czeladz.pl +czest.pl +dlugoleka.pl +elblag.pl +elk.pl +glogow.pl +gniezno.pl +gorlice.pl +grajewo.pl +ilawa.pl +jaworzno.pl +jelenia-gora.pl +jgora.pl +kalisz.pl +kazimierz-dolny.pl +karpacz.pl +kartuzy.pl +kaszuby.pl +katowice.pl +kepno.pl +ketrzyn.pl +klodzko.pl +kobierzyce.pl +kolobrzeg.pl +konin.pl +konskowola.pl +kutno.pl +lapy.pl +lebork.pl +legnica.pl +lezajsk.pl +limanowa.pl +lomza.pl +lowicz.pl +lubin.pl +lukow.pl +malbork.pl +malopolska.pl +mazowsze.pl +mazury.pl +mielec.pl +mielno.pl +mragowo.pl +naklo.pl +nowaruda.pl +nysa.pl +olawa.pl +olecko.pl +olkusz.pl +olsztyn.pl +opoczno.pl +opole.pl +ostroda.pl +ostroleka.pl +ostrowiec.pl +ostrowwlkp.pl +pila.pl +pisz.pl +podhale.pl +podlasie.pl +polkowice.pl +pomorze.pl +pomorskie.pl +prochowice.pl +pruszkow.pl +przeworsk.pl +pulawy.pl +radom.pl +rawa-maz.pl +rybnik.pl +rzeszow.pl +sanok.pl +sejny.pl +slask.pl +slupsk.pl +sosnowiec.pl +stalowa-wola.pl +skoczow.pl +starachowice.pl +stargard.pl +suwalki.pl +swidnica.pl +swiebodzin.pl +swinoujscie.pl +szczecin.pl +szczytno.pl +tarnobrzeg.pl +tgory.pl +turek.pl +tychy.pl +ustka.pl +walbrzych.pl +warmia.pl +warszawa.pl +waw.pl +wegrow.pl +wielun.pl +wlocl.pl +wloclawek.pl +wodzislaw.pl +wolomin.pl +wroclaw.pl +zachpomor.pl +zagan.pl +zarow.pl +zgora.pl +zgorzelec.pl + +// pm : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf +pm + +// pn : http://www.government.pn/PnRegistry/policies.htm +pn +gov.pn +co.pn +org.pn +edu.pn +net.pn + +// post : https://en.wikipedia.org/wiki/.post +post + +// pr : http://www.nic.pr/index.asp?f=1 +pr +com.pr +net.pr +org.pr +gov.pr +edu.pr +isla.pr +pro.pr +biz.pr +info.pr +name.pr +// these aren't mentioned on nic.pr, but on https://en.wikipedia.org/wiki/.pr +est.pr +prof.pr +ac.pr + +// pro : http://registry.pro/get-pro +pro +aaa.pro +aca.pro +acct.pro +avocat.pro +bar.pro +cpa.pro +eng.pro +jur.pro +law.pro +med.pro +recht.pro + +// ps : https://en.wikipedia.org/wiki/.ps +// http://www.nic.ps/registration/policy.html#reg +ps +edu.ps +gov.ps +sec.ps +plo.ps +com.ps +org.ps +net.ps + +// pt : http://online.dns.pt/dns/start_dns +pt +net.pt +gov.pt +org.pt +edu.pt +int.pt +publ.pt +com.pt +nome.pt + +// pw : https://en.wikipedia.org/wiki/.pw +pw +co.pw +ne.pw +or.pw +ed.pw +go.pw +belau.pw + +// py : http://www.nic.py/pautas.html#seccion_9 +// Submitted by registry +py +com.py +coop.py +edu.py +gov.py +mil.py +net.py +org.py + +// qa : http://domains.qa/en/ +qa +com.qa +edu.qa +gov.qa +mil.qa +name.qa +net.qa +org.qa +sch.qa + +// re : http://www.afnic.re/obtenir/chartes/nommage-re/annexe-descriptifs +re +asso.re +com.re +nom.re + +// ro : http://www.rotld.ro/ +ro +arts.ro +com.ro +firm.ro +info.ro +nom.ro +nt.ro +org.ro +rec.ro +store.ro +tm.ro +www.ro + +// rs : https://www.rnids.rs/en/domains/national-domains +rs +ac.rs +co.rs +edu.rs +gov.rs +in.rs +org.rs + +// ru : https://cctld.ru/files/pdf/docs/en/rules_ru-rf.pdf +// Submitted by George Georgievsky +ru + +// rw : https://www.ricta.org.rw/sites/default/files/resources/registry_registrar_contract_0.pdf +rw +ac.rw +co.rw +coop.rw +gov.rw +mil.rw +net.rw +org.rw + +// sa : http://www.nic.net.sa/ +sa +com.sa +net.sa +org.sa +gov.sa +med.sa +pub.sa +edu.sa +sch.sa + +// sb : http://www.sbnic.net.sb/ +// Submitted by registry +sb +com.sb +edu.sb +gov.sb +net.sb +org.sb + +// sc : http://www.nic.sc/ +sc +com.sc +gov.sc +net.sc +org.sc +edu.sc + +// sd : http://www.isoc.sd/sudanic.isoc.sd/billing_pricing.htm +// Submitted by registry +sd +com.sd +net.sd +org.sd +edu.sd +med.sd +tv.sd +gov.sd +info.sd + +// se : https://en.wikipedia.org/wiki/.se +// Submitted by registry +se +a.se +ac.se +b.se +bd.se +brand.se +c.se +d.se +e.se +f.se +fh.se +fhsk.se +fhv.se +g.se +h.se +i.se +k.se +komforb.se +kommunalforbund.se +komvux.se +l.se +lanbib.se +m.se +n.se +naturbruksgymn.se +o.se +org.se +p.se +parti.se +pp.se +press.se +r.se +s.se +t.se +tm.se +u.se +w.se +x.se +y.se +z.se + +// sg : http://www.nic.net.sg/page/registration-policies-procedures-and-guidelines +sg +com.sg +net.sg +org.sg +gov.sg +edu.sg +per.sg + +// sh : http://www.nic.sh/registrar.html +sh +com.sh +net.sh +gov.sh +org.sh +mil.sh + +// si : https://en.wikipedia.org/wiki/.si +si + +// sj : No registrations at this time. +// Submitted by registry +sj + +// sk : https://en.wikipedia.org/wiki/.sk +// list of 2nd level domains ? +sk + +// sl : http://www.nic.sl +// Submitted by registry +sl +com.sl +net.sl +edu.sl +gov.sl +org.sl + +// sm : https://en.wikipedia.org/wiki/.sm +sm + +// sn : https://en.wikipedia.org/wiki/.sn +sn +art.sn +com.sn +edu.sn +gouv.sn +org.sn +perso.sn +univ.sn + +// so : http://sonic.so/policies/ +so +com.so +edu.so +gov.so +me.so +net.so +org.so + +// sr : https://en.wikipedia.org/wiki/.sr +sr + +// ss : https://registry.nic.ss/ +// Submitted by registry +ss +biz.ss +com.ss +edu.ss +gov.ss +net.ss +org.ss + +// st : http://www.nic.st/html/policyrules/ +st +co.st +com.st +consulado.st +edu.st +embaixada.st +gov.st +mil.st +net.st +org.st +principe.st +saotome.st +store.st + +// su : https://en.wikipedia.org/wiki/.su +su + +// sv : http://www.svnet.org.sv/niveldos.pdf +sv +com.sv +edu.sv +gob.sv +org.sv +red.sv + +// sx : https://en.wikipedia.org/wiki/.sx +// Submitted by registry +sx +gov.sx + +// sy : https://en.wikipedia.org/wiki/.sy +// see also: http://www.gobin.info/domainname/sy.doc +sy +edu.sy +gov.sy +net.sy +mil.sy +com.sy +org.sy + +// sz : https://en.wikipedia.org/wiki/.sz +// http://www.sispa.org.sz/ +sz +co.sz +ac.sz +org.sz + +// tc : https://en.wikipedia.org/wiki/.tc +tc + +// td : https://en.wikipedia.org/wiki/.td +td + +// tel: https://en.wikipedia.org/wiki/.tel +// http://www.telnic.org/ +tel + +// tf : https://en.wikipedia.org/wiki/.tf +tf + +// tg : https://en.wikipedia.org/wiki/.tg +// http://www.nic.tg/ +tg + +// th : https://en.wikipedia.org/wiki/.th +// Submitted by registry +th +ac.th +co.th +go.th +in.th +mi.th +net.th +or.th + +// tj : http://www.nic.tj/policy.html +tj +ac.tj +biz.tj +co.tj +com.tj +edu.tj +go.tj +gov.tj +int.tj +mil.tj +name.tj +net.tj +nic.tj +org.tj +test.tj +web.tj + +// tk : https://en.wikipedia.org/wiki/.tk +tk + +// tl : https://en.wikipedia.org/wiki/.tl +tl +gov.tl + +// tm : http://www.nic.tm/local.html +tm +com.tm +co.tm +org.tm +net.tm +nom.tm +gov.tm +mil.tm +edu.tm + +// tn : https://en.wikipedia.org/wiki/.tn +// http://whois.ati.tn/ +tn +com.tn +ens.tn +fin.tn +gov.tn +ind.tn +intl.tn +nat.tn +net.tn +org.tn +info.tn +perso.tn +tourism.tn +edunet.tn +rnrt.tn +rns.tn +rnu.tn +mincom.tn +agrinet.tn +defense.tn +turen.tn + +// to : https://en.wikipedia.org/wiki/.to +// Submitted by registry +to +com.to +gov.to +net.to +org.to +edu.to +mil.to + +// tr : https://nic.tr/ +// https://nic.tr/forms/eng/policies.pdf +// https://nic.tr/index.php?USRACTN=PRICELST +tr +av.tr +bbs.tr +bel.tr +biz.tr +com.tr +dr.tr +edu.tr +gen.tr +gov.tr +info.tr +mil.tr +k12.tr +kep.tr +name.tr +net.tr +org.tr +pol.tr +tel.tr +tsk.tr +tv.tr +web.tr +// Used by Northern Cyprus +nc.tr +// Used by government agencies of Northern Cyprus +gov.nc.tr + +// tt : http://www.nic.tt/ +tt +co.tt +com.tt +org.tt +net.tt +biz.tt +info.tt +pro.tt +int.tt +coop.tt +jobs.tt +mobi.tt +travel.tt +museum.tt +aero.tt +name.tt +gov.tt +edu.tt + +// tv : https://en.wikipedia.org/wiki/.tv +// Not listing any 2LDs as reserved since none seem to exist in practice, +// Wikipedia notwithstanding. +tv + +// tw : https://en.wikipedia.org/wiki/.tw +tw +edu.tw +gov.tw +mil.tw +com.tw +net.tw +org.tw +idv.tw +game.tw +ebiz.tw +club.tw +網路.tw +組織.tw +商業.tw + +// tz : http://www.tznic.or.tz/index.php/domains +// Submitted by registry +tz +ac.tz +co.tz +go.tz +hotel.tz +info.tz +me.tz +mil.tz +mobi.tz +ne.tz +or.tz +sc.tz +tv.tz + +// ua : https://hostmaster.ua/policy/?ua +// Submitted by registry +ua +// ua 2LD +com.ua +edu.ua +gov.ua +in.ua +net.ua +org.ua +// ua geographic names +// https://hostmaster.ua/2ld/ +cherkassy.ua +cherkasy.ua +chernigov.ua +chernihiv.ua +chernivtsi.ua +chernovtsy.ua +ck.ua +cn.ua +cr.ua +crimea.ua +cv.ua +dn.ua +dnepropetrovsk.ua +dnipropetrovsk.ua +donetsk.ua +dp.ua +if.ua +ivano-frankivsk.ua +kh.ua +kharkiv.ua +kharkov.ua +kherson.ua +khmelnitskiy.ua +khmelnytskyi.ua +kiev.ua +kirovograd.ua +km.ua +kr.ua +krym.ua +ks.ua +kv.ua +kyiv.ua +lg.ua +lt.ua +lugansk.ua +lutsk.ua +lv.ua +lviv.ua +mk.ua +mykolaiv.ua +nikolaev.ua +od.ua +odesa.ua +odessa.ua +pl.ua +poltava.ua +rivne.ua +rovno.ua +rv.ua +sb.ua +sebastopol.ua +sevastopol.ua +sm.ua +sumy.ua +te.ua +ternopil.ua +uz.ua +uzhgorod.ua +vinnica.ua +vinnytsia.ua +vn.ua +volyn.ua +yalta.ua +zaporizhzhe.ua +zaporizhzhia.ua +zhitomir.ua +zhytomyr.ua +zp.ua +zt.ua + +// ug : https://www.registry.co.ug/ +ug +co.ug +or.ug +ac.ug +sc.ug +go.ug +ne.ug +com.ug +org.ug + +// uk : https://en.wikipedia.org/wiki/.uk +// Submitted by registry +uk +ac.uk +co.uk +gov.uk +ltd.uk +me.uk +net.uk +nhs.uk +org.uk +plc.uk +police.uk +*.sch.uk + +// us : https://en.wikipedia.org/wiki/.us +us +dni.us +fed.us +isa.us +kids.us +nsn.us +// us geographic names +ak.us +al.us +ar.us +as.us +az.us +ca.us +co.us +ct.us +dc.us +de.us +fl.us +ga.us +gu.us +hi.us +ia.us +id.us +il.us +in.us +ks.us +ky.us +la.us +ma.us +md.us +me.us +mi.us +mn.us +mo.us +ms.us +mt.us +nc.us +nd.us +ne.us +nh.us +nj.us +nm.us +nv.us +ny.us +oh.us +ok.us +or.us +pa.us +pr.us +ri.us +sc.us +sd.us +tn.us +tx.us +ut.us +vi.us +vt.us +va.us +wa.us +wi.us +wv.us +wy.us +// The registrar notes several more specific domains available in each state, +// such as state.*.us, dst.*.us, etc., but resolution of these is somewhat +// haphazard; in some states these domains resolve as addresses, while in others +// only subdomains are available, or even nothing at all. We include the +// most common ones where it's clear that different sites are different +// entities. +k12.ak.us +k12.al.us +k12.ar.us +k12.as.us +k12.az.us +k12.ca.us +k12.co.us +k12.ct.us +k12.dc.us +k12.de.us +k12.fl.us +k12.ga.us +k12.gu.us +// k12.hi.us Bug 614565 - Hawaii has a state-wide DOE login +k12.ia.us +k12.id.us +k12.il.us +k12.in.us +k12.ks.us +k12.ky.us +k12.la.us +k12.ma.us +k12.md.us +k12.me.us +k12.mi.us +k12.mn.us +k12.mo.us +k12.ms.us +k12.mt.us +k12.nc.us +// k12.nd.us Bug 1028347 - Removed at request of Travis Rosso +k12.ne.us +k12.nh.us +k12.nj.us +k12.nm.us +k12.nv.us +k12.ny.us +k12.oh.us +k12.ok.us +k12.or.us +k12.pa.us +k12.pr.us +// k12.ri.us Removed at request of Kim Cournoyer +k12.sc.us +// k12.sd.us Bug 934131 - Removed at request of James Booze +k12.tn.us +k12.tx.us +k12.ut.us +k12.vi.us +k12.vt.us +k12.va.us +k12.wa.us +k12.wi.us +// k12.wv.us Bug 947705 - Removed at request of Verne Britton +k12.wy.us +cc.ak.us +cc.al.us +cc.ar.us +cc.as.us +cc.az.us +cc.ca.us +cc.co.us +cc.ct.us +cc.dc.us +cc.de.us +cc.fl.us +cc.ga.us +cc.gu.us +cc.hi.us +cc.ia.us +cc.id.us +cc.il.us +cc.in.us +cc.ks.us +cc.ky.us +cc.la.us +cc.ma.us +cc.md.us +cc.me.us +cc.mi.us +cc.mn.us +cc.mo.us +cc.ms.us +cc.mt.us +cc.nc.us +cc.nd.us +cc.ne.us +cc.nh.us +cc.nj.us +cc.nm.us +cc.nv.us +cc.ny.us +cc.oh.us +cc.ok.us +cc.or.us +cc.pa.us +cc.pr.us +cc.ri.us +cc.sc.us +cc.sd.us +cc.tn.us +cc.tx.us +cc.ut.us +cc.vi.us +cc.vt.us +cc.va.us +cc.wa.us +cc.wi.us +cc.wv.us +cc.wy.us +lib.ak.us +lib.al.us +lib.ar.us +lib.as.us +lib.az.us +lib.ca.us +lib.co.us +lib.ct.us +lib.dc.us +// lib.de.us Issue #243 - Moved to Private section at request of Ed Moore +lib.fl.us +lib.ga.us +lib.gu.us +lib.hi.us +lib.ia.us +lib.id.us +lib.il.us +lib.in.us +lib.ks.us +lib.ky.us +lib.la.us +lib.ma.us +lib.md.us +lib.me.us +lib.mi.us +lib.mn.us +lib.mo.us +lib.ms.us +lib.mt.us +lib.nc.us +lib.nd.us +lib.ne.us +lib.nh.us +lib.nj.us +lib.nm.us +lib.nv.us +lib.ny.us +lib.oh.us +lib.ok.us +lib.or.us +lib.pa.us +lib.pr.us +lib.ri.us +lib.sc.us +lib.sd.us +lib.tn.us +lib.tx.us +lib.ut.us +lib.vi.us +lib.vt.us +lib.va.us +lib.wa.us +lib.wi.us +// lib.wv.us Bug 941670 - Removed at request of Larry W Arnold +lib.wy.us +// k12.ma.us contains school districts in Massachusetts. The 4LDs are +// managed independently except for private (PVT), charter (CHTR) and +// parochial (PAROCH) schools. Those are delegated directly to the +// 5LD operators. +pvt.k12.ma.us +chtr.k12.ma.us +paroch.k12.ma.us +// Merit Network, Inc. maintains the registry for =~ /(k12|cc|lib).mi.us/ and the following +// see also: http://domreg.merit.edu +// see also: whois -h whois.domreg.merit.edu help +ann-arbor.mi.us +cog.mi.us +dst.mi.us +eaton.mi.us +gen.mi.us +mus.mi.us +tec.mi.us +washtenaw.mi.us + +// uy : http://www.nic.org.uy/ +uy +com.uy +edu.uy +gub.uy +mil.uy +net.uy +org.uy + +// uz : http://www.reg.uz/ +uz +co.uz +com.uz +net.uz +org.uz + +// va : https://en.wikipedia.org/wiki/.va +va + +// vc : https://en.wikipedia.org/wiki/.vc +// Submitted by registry +vc +com.vc +net.vc +org.vc +gov.vc +mil.vc +edu.vc + +// ve : https://registro.nic.ve/ +// Submitted by registry +ve +arts.ve +co.ve +com.ve +e12.ve +edu.ve +firm.ve +gob.ve +gov.ve +info.ve +int.ve +mil.ve +net.ve +org.ve +rec.ve +store.ve +tec.ve +web.ve + +// vg : https://en.wikipedia.org/wiki/.vg +vg + +// vi : http://www.nic.vi/newdomainform.htm +// http://www.nic.vi/Domain_Rules/body_domain_rules.html indicates some other +// TLDs are "reserved", such as edu.vi and gov.vi, but doesn't actually say they +// are available for registration (which they do not seem to be). +vi +co.vi +com.vi +k12.vi +net.vi +org.vi + +// vn : https://www.dot.vn/vnnic/vnnic/domainregistration.jsp +vn +com.vn +net.vn +org.vn +edu.vn +gov.vn +int.vn +ac.vn +biz.vn +info.vn +name.vn +pro.vn +health.vn + +// vu : https://en.wikipedia.org/wiki/.vu +// http://www.vunic.vu/ +vu +com.vu +edu.vu +net.vu +org.vu + +// wf : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf +wf + +// ws : https://en.wikipedia.org/wiki/.ws +// http://samoanic.ws/index.dhtml +ws +com.ws +net.ws +org.ws +gov.ws +edu.ws + +// yt : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf +yt + +// IDN ccTLDs +// When submitting patches, please maintain a sort by ISO 3166 ccTLD, then +// U-label, and follow this format: +// // A-Label ("", [, variant info]) : +// // [sponsoring org] +// U-Label + +// xn--mgbaam7a8h ("Emerat", Arabic) : AE +// http://nic.ae/english/arabicdomain/rules.jsp +امارات + +// xn--y9a3aq ("hye", Armenian) : AM +// ISOC AM (operated by .am Registry) +հայ + +// xn--54b7fta0cc ("Bangla", Bangla) : BD +বাংলা + +// xn--90ae ("bg", Bulgarian) : BG +бг + +// xn--90ais ("bel", Belarusian/Russian Cyrillic) : BY +// Operated by .by registry +бел + +// xn--fiqs8s ("Zhongguo/China", Chinese, Simplified) : CN +// CNNIC +// http://cnnic.cn/html/Dir/2005/10/11/3218.htm +中国 + +// xn--fiqz9s ("Zhongguo/China", Chinese, Traditional) : CN +// CNNIC +// http://cnnic.cn/html/Dir/2005/10/11/3218.htm +中國 + +// xn--lgbbat1ad8j ("Algeria/Al Jazair", Arabic) : DZ +الجزائر + +// xn--wgbh1c ("Egypt/Masr", Arabic) : EG +// http://www.dotmasr.eg/ +مصر + +// xn--e1a4c ("eu", Cyrillic) : EU +// https://eurid.eu +ею + +// xn--qxa6a ("eu", Greek) : EU +// https://eurid.eu +ευ + +// xn--mgbah1a3hjkrd ("Mauritania", Arabic) : MR +موريتانيا + +// xn--node ("ge", Georgian Mkhedruli) : GE +გე + +// xn--qxam ("el", Greek) : GR +// Hellenic Ministry of Infrastructure, Transport, and Networks +ελ + +// xn--j6w193g ("Hong Kong", Chinese) : HK +// https://www.hkirc.hk +// Submitted by registry +// https://www.hkirc.hk/content.jsp?id=30#!/34 +香港 +公司.香港 +教育.香港 +政府.香港 +個人.香港 +網絡.香港 +組織.香港 + +// xn--2scrj9c ("Bharat", Kannada) : IN +// India +ಭಾರತ + +// xn--3hcrj9c ("Bharat", Oriya) : IN +// India +ଭାରତ + +// xn--45br5cyl ("Bharatam", Assamese) : IN +// India +ভাৰত + +// xn--h2breg3eve ("Bharatam", Sanskrit) : IN +// India +भारतम् + +// xn--h2brj9c8c ("Bharot", Santali) : IN +// India +भारोत + +// xn--mgbgu82a ("Bharat", Sindhi) : IN +// India +ڀارت + +// xn--rvc1e0am3e ("Bharatam", Malayalam) : IN +// India +ഭാരതം + +// xn--h2brj9c ("Bharat", Devanagari) : IN +// India +भारत + +// xn--mgbbh1a ("Bharat", Kashmiri) : IN +// India +بارت + +// xn--mgbbh1a71e ("Bharat", Arabic) : IN +// India +بھارت + +// xn--fpcrj9c3d ("Bharat", Telugu) : IN +// India +భారత్ + +// xn--gecrj9c ("Bharat", Gujarati) : IN +// India +ભારત + +// xn--s9brj9c ("Bharat", Gurmukhi) : IN +// India +ਭਾਰਤ + +// xn--45brj9c ("Bharat", Bengali) : IN +// India +ভারত + +// xn--xkc2dl3a5ee0h ("India", Tamil) : IN +// India +இந்தியா + +// xn--mgba3a4f16a ("Iran", Persian) : IR +ایران + +// xn--mgba3a4fra ("Iran", Arabic) : IR +ايران + +// xn--mgbtx2b ("Iraq", Arabic) : IQ +// Communications and Media Commission +عراق + +// xn--mgbayh7gpa ("al-Ordon", Arabic) : JO +// National Information Technology Center (NITC) +// Royal Scientific Society, Al-Jubeiha +الاردن + +// xn--3e0b707e ("Republic of Korea", Hangul) : KR +한국 + +// xn--80ao21a ("Kaz", Kazakh) : KZ +қаз + +// xn--fzc2c9e2c ("Lanka", Sinhalese-Sinhala) : LK +// https://nic.lk +ලංකා + +// xn--xkc2al3hye2a ("Ilangai", Tamil) : LK +// https://nic.lk +இலங்கை + +// xn--mgbc0a9azcg ("Morocco/al-Maghrib", Arabic) : MA +المغرب + +// xn--d1alf ("mkd", Macedonian) : MK +// MARnet +мкд + +// xn--l1acc ("mon", Mongolian) : MN +мон + +// xn--mix891f ("Macao", Chinese, Traditional) : MO +// MONIC / HNET Asia (Registry Operator for .mo) +澳門 + +// xn--mix082f ("Macao", Chinese, Simplified) : MO +澳门 + +// xn--mgbx4cd0ab ("Malaysia", Malay) : MY +مليسيا + +// xn--mgb9awbf ("Oman", Arabic) : OM +عمان + +// xn--mgbai9azgqp6j ("Pakistan", Urdu/Arabic) : PK +پاکستان + +// xn--mgbai9a5eva00b ("Pakistan", Urdu/Arabic, variant) : PK +پاكستان + +// xn--ygbi2ammx ("Falasteen", Arabic) : PS +// The Palestinian National Internet Naming Authority (PNINA) +// http://www.pnina.ps +فلسطين + +// xn--90a3ac ("srb", Cyrillic) : RS +// https://www.rnids.rs/en/domains/national-domains +срб +пр.срб +орг.срб +обр.срб +од.срб +упр.срб +ак.срб + +// xn--p1ai ("rf", Russian-Cyrillic) : RU +// https://cctld.ru/files/pdf/docs/en/rules_ru-rf.pdf +// Submitted by George Georgievsky +рф + +// xn--wgbl6a ("Qatar", Arabic) : QA +// http://www.ict.gov.qa/ +قطر + +// xn--mgberp4a5d4ar ("AlSaudiah", Arabic) : SA +// http://www.nic.net.sa/ +السعودية + +// xn--mgberp4a5d4a87g ("AlSaudiah", Arabic, variant) : SA +السعودیة + +// xn--mgbqly7c0a67fbc ("AlSaudiah", Arabic, variant) : SA +السعودیۃ + +// xn--mgbqly7cvafr ("AlSaudiah", Arabic, variant) : SA +السعوديه + +// xn--mgbpl2fh ("sudan", Arabic) : SD +// Operated by .sd registry +سودان + +// xn--yfro4i67o Singapore ("Singapore", Chinese) : SG +新加坡 + +// xn--clchc0ea0b2g2a9gcd ("Singapore", Tamil) : SG +சிங்கப்பூர் + +// xn--ogbpf8fl ("Syria", Arabic) : SY +سورية + +// xn--mgbtf8fl ("Syria", Arabic, variant) : SY +سوريا + +// xn--o3cw4h ("Thai", Thai) : TH +// http://www.thnic.co.th +ไทย +ศึกษา.ไทย +ธุรกิจ.ไทย +รัฐบาล.ไทย +ทหาร.ไทย +เน็ต.ไทย +องค์กร.ไทย + +// xn--pgbs0dh ("Tunisia", Arabic) : TN +// http://nic.tn +تونس + +// xn--kpry57d ("Taiwan", Chinese, Traditional) : TW +// http://www.twnic.net/english/dn/dn_07a.htm +台灣 + +// xn--kprw13d ("Taiwan", Chinese, Simplified) : TW +// http://www.twnic.net/english/dn/dn_07a.htm +台湾 + +// xn--nnx388a ("Taiwan", Chinese, variant) : TW +臺灣 + +// xn--j1amh ("ukr", Cyrillic) : UA +укр + +// xn--mgb2ddes ("AlYemen", Arabic) : YE +اليمن + +// xxx : http://icmregistry.com +xxx + +// ye : http://www.y.net.ye/services/domain_name.htm +*.ye + +// za : https://www.zadna.org.za/content/page/domain-information/ +ac.za +agric.za +alt.za +co.za +edu.za +gov.za +grondar.za +law.za +mil.za +net.za +ngo.za +nic.za +nis.za +nom.za +org.za +school.za +tm.za +web.za + +// zm : https://zicta.zm/ +// Submitted by registry +zm +ac.zm +biz.zm +co.zm +com.zm +edu.zm +gov.zm +info.zm +mil.zm +net.zm +org.zm +sch.zm + +// zw : https://www.potraz.gov.zw/ +// Confirmed by registry 2017-01-25 +zw +ac.zw +co.zw +gov.zw +mil.zw +org.zw + + +// newGTLDs + +// List of new gTLDs imported from https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 2020-11-21T18:09:21Z +// This list is auto-generated, don't edit it manually. +// aaa : 2015-02-26 American Automobile Association, Inc. +aaa + +// aarp : 2015-05-21 AARP +aarp + +// abarth : 2015-07-30 Fiat Chrysler Automobiles N.V. +abarth + +// abb : 2014-10-24 ABB Ltd +abb + +// abbott : 2014-07-24 Abbott Laboratories, Inc. +abbott + +// abbvie : 2015-07-30 AbbVie Inc. +abbvie + +// abc : 2015-07-30 Disney Enterprises, Inc. +abc + +// able : 2015-06-25 Able Inc. +able + +// abogado : 2014-04-24 Minds + Machines Group Limited +abogado + +// abudhabi : 2015-07-30 Abu Dhabi Systems and Information Centre +abudhabi + +// academy : 2013-11-07 Binky Moon, LLC +academy + +// accenture : 2014-08-15 Accenture plc +accenture + +// accountant : 2014-11-20 dot Accountant Limited +accountant + +// accountants : 2014-03-20 Binky Moon, LLC +accountants + +// aco : 2015-01-08 ACO Severin Ahlmann GmbH & Co. KG +aco + +// actor : 2013-12-12 Dog Beach, LLC +actor + +// adac : 2015-07-16 Allgemeiner Deutscher Automobil-Club e.V. (ADAC) +adac + +// ads : 2014-12-04 Charleston Road Registry Inc. +ads + +// adult : 2014-10-16 ICM Registry AD LLC +adult + +// aeg : 2015-03-19 Aktiebolaget Electrolux +aeg + +// aetna : 2015-05-21 Aetna Life Insurance Company +aetna + +// afamilycompany : 2015-07-23 Johnson Shareholdings, Inc. +afamilycompany + +// afl : 2014-10-02 Australian Football League +afl + +// africa : 2014-03-24 ZA Central Registry NPC trading as Registry.Africa +africa + +// agakhan : 2015-04-23 Fondation Aga Khan (Aga Khan Foundation) +agakhan + +// agency : 2013-11-14 Binky Moon, LLC +agency + +// aig : 2014-12-18 American International Group, Inc. +aig + +// airbus : 2015-07-30 Airbus S.A.S. +airbus + +// airforce : 2014-03-06 Dog Beach, LLC +airforce + +// airtel : 2014-10-24 Bharti Airtel Limited +airtel + +// akdn : 2015-04-23 Fondation Aga Khan (Aga Khan Foundation) +akdn + +// alfaromeo : 2015-07-31 Fiat Chrysler Automobiles N.V. +alfaromeo + +// alibaba : 2015-01-15 Alibaba Group Holding Limited +alibaba + +// alipay : 2015-01-15 Alibaba Group Holding Limited +alipay + +// allfinanz : 2014-07-03 Allfinanz Deutsche Vermögensberatung Aktiengesellschaft +allfinanz + +// allstate : 2015-07-31 Allstate Fire and Casualty Insurance Company +allstate + +// ally : 2015-06-18 Ally Financial Inc. +ally + +// alsace : 2014-07-02 Region Grand Est +alsace + +// alstom : 2015-07-30 ALSTOM +alstom + +// amazon : 2019-12-19 Amazon Registry Services, Inc. +amazon + +// americanexpress : 2015-07-31 American Express Travel Related Services Company, Inc. +americanexpress + +// americanfamily : 2015-07-23 AmFam, Inc. +americanfamily + +// amex : 2015-07-31 American Express Travel Related Services Company, Inc. +amex + +// amfam : 2015-07-23 AmFam, Inc. +amfam + +// amica : 2015-05-28 Amica Mutual Insurance Company +amica + +// amsterdam : 2014-07-24 Gemeente Amsterdam +amsterdam + +// analytics : 2014-12-18 Campus IP LLC +analytics + +// android : 2014-08-07 Charleston Road Registry Inc. +android + +// anquan : 2015-01-08 Beijing Qihu Keji Co., Ltd. +anquan + +// anz : 2015-07-31 Australia and New Zealand Banking Group Limited +anz + +// aol : 2015-09-17 Oath Inc. +aol + +// apartments : 2014-12-11 Binky Moon, LLC +apartments + +// app : 2015-05-14 Charleston Road Registry Inc. +app + +// apple : 2015-05-14 Apple Inc. +apple + +// aquarelle : 2014-07-24 Aquarelle.com +aquarelle + +// arab : 2015-11-12 League of Arab States +arab + +// aramco : 2014-11-20 Aramco Services Company +aramco + +// archi : 2014-02-06 Afilias Limited +archi + +// army : 2014-03-06 Dog Beach, LLC +army + +// art : 2016-03-24 UK Creative Ideas Limited +art + +// arte : 2014-12-11 Association Relative à la Télévision Européenne G.E.I.E. +arte + +// asda : 2015-07-31 Wal-Mart Stores, Inc. +asda + +// associates : 2014-03-06 Binky Moon, LLC +associates + +// athleta : 2015-07-30 The Gap, Inc. +athleta + +// attorney : 2014-03-20 Dog Beach, LLC +attorney + +// auction : 2014-03-20 Dog Beach, LLC +auction + +// audi : 2015-05-21 AUDI Aktiengesellschaft +audi + +// audible : 2015-06-25 Amazon Registry Services, Inc. +audible + +// audio : 2014-03-20 UNR Corp. +audio + +// auspost : 2015-08-13 Australian Postal Corporation +auspost + +// author : 2014-12-18 Amazon Registry Services, Inc. +author + +// auto : 2014-11-13 XYZ.COM LLC +auto + +// autos : 2014-01-09 XYZ.COM LLC +autos + +// avianca : 2015-01-08 Avianca Holdings S.A. +avianca + +// aws : 2015-06-25 Amazon Registry Services, Inc. +aws + +// axa : 2013-12-19 AXA Group Operations SAS +axa + +// azure : 2014-12-18 Microsoft Corporation +azure + +// baby : 2015-04-09 XYZ.COM LLC +baby + +// baidu : 2015-01-08 Baidu, Inc. +baidu + +// banamex : 2015-07-30 Citigroup Inc. +banamex + +// bananarepublic : 2015-07-31 The Gap, Inc. +bananarepublic + +// band : 2014-06-12 Dog Beach, LLC +band + +// bank : 2014-09-25 fTLD Registry Services LLC +bank + +// bar : 2013-12-12 Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable +bar + +// barcelona : 2014-07-24 Municipi de Barcelona +barcelona + +// barclaycard : 2014-11-20 Barclays Bank PLC +barclaycard + +// barclays : 2014-11-20 Barclays Bank PLC +barclays + +// barefoot : 2015-06-11 Gallo Vineyards, Inc. +barefoot + +// bargains : 2013-11-14 Binky Moon, LLC +bargains + +// baseball : 2015-10-29 MLB Advanced Media DH, LLC +baseball + +// basketball : 2015-08-20 Fédération Internationale de Basketball (FIBA) +basketball + +// bauhaus : 2014-04-17 Werkhaus GmbH +bauhaus + +// bayern : 2014-01-23 Bayern Connect GmbH +bayern + +// bbc : 2014-12-18 British Broadcasting Corporation +bbc + +// bbt : 2015-07-23 BB&T Corporation +bbt + +// bbva : 2014-10-02 BANCO BILBAO VIZCAYA ARGENTARIA, S.A. +bbva + +// bcg : 2015-04-02 The Boston Consulting Group, Inc. +bcg + +// bcn : 2014-07-24 Municipi de Barcelona +bcn + +// beats : 2015-05-14 Beats Electronics, LLC +beats + +// beauty : 2015-12-03 XYZ.COM LLC +beauty + +// beer : 2014-01-09 Minds + Machines Group Limited +beer + +// bentley : 2014-12-18 Bentley Motors Limited +bentley + +// berlin : 2013-10-31 dotBERLIN GmbH & Co. KG +berlin + +// best : 2013-12-19 BestTLD Pty Ltd +best + +// bestbuy : 2015-07-31 BBY Solutions, Inc. +bestbuy + +// bet : 2015-05-07 Afilias Limited +bet + +// bharti : 2014-01-09 Bharti Enterprises (Holding) Private Limited +bharti + +// bible : 2014-06-19 American Bible Society +bible + +// bid : 2013-12-19 dot Bid Limited +bid + +// bike : 2013-08-27 Binky Moon, LLC +bike + +// bing : 2014-12-18 Microsoft Corporation +bing + +// bingo : 2014-12-04 Binky Moon, LLC +bingo + +// bio : 2014-03-06 Afilias Limited +bio + +// black : 2014-01-16 Afilias Limited +black + +// blackfriday : 2014-01-16 UNR Corp. +blackfriday + +// blockbuster : 2015-07-30 Dish DBS Corporation +blockbuster + +// blog : 2015-05-14 Knock Knock WHOIS There, LLC +blog + +// bloomberg : 2014-07-17 Bloomberg IP Holdings LLC +bloomberg + +// blue : 2013-11-07 Afilias Limited +blue + +// bms : 2014-10-30 Bristol-Myers Squibb Company +bms + +// bmw : 2014-01-09 Bayerische Motoren Werke Aktiengesellschaft +bmw + +// bnpparibas : 2014-05-29 BNP Paribas +bnpparibas + +// boats : 2014-12-04 XYZ.COM LLC +boats + +// boehringer : 2015-07-09 Boehringer Ingelheim International GmbH +boehringer + +// bofa : 2015-07-31 Bank of America Corporation +bofa + +// bom : 2014-10-16 Núcleo de Informação e Coordenação do Ponto BR - NIC.br +bom + +// bond : 2014-06-05 ShortDot SA +bond + +// boo : 2014-01-30 Charleston Road Registry Inc. +boo + +// book : 2015-08-27 Amazon Registry Services, Inc. +book + +// booking : 2015-07-16 Booking.com B.V. +booking + +// bosch : 2015-06-18 Robert Bosch GMBH +bosch + +// bostik : 2015-05-28 Bostik SA +bostik + +// boston : 2015-12-10 Boston TLD Management, LLC +boston + +// bot : 2014-12-18 Amazon Registry Services, Inc. +bot + +// boutique : 2013-11-14 Binky Moon, LLC +boutique + +// box : 2015-11-12 Intercap Registry Inc. +box + +// bradesco : 2014-12-18 Banco Bradesco S.A. +bradesco + +// bridgestone : 2014-12-18 Bridgestone Corporation +bridgestone + +// broadway : 2014-12-22 Celebrate Broadway, Inc. +broadway + +// broker : 2014-12-11 Dotbroker Registry Limited +broker + +// brother : 2015-01-29 Brother Industries, Ltd. +brother + +// brussels : 2014-02-06 DNS.be vzw +brussels + +// budapest : 2013-11-21 Minds + Machines Group Limited +budapest + +// bugatti : 2015-07-23 Bugatti International SA +bugatti + +// build : 2013-11-07 Plan Bee LLC +build + +// builders : 2013-11-07 Binky Moon, LLC +builders + +// business : 2013-11-07 Binky Moon, LLC +business + +// buy : 2014-12-18 Amazon Registry Services, Inc. +buy + +// buzz : 2013-10-02 DOTSTRATEGY CO. +buzz + +// bzh : 2014-02-27 Association www.bzh +bzh + +// cab : 2013-10-24 Binky Moon, LLC +cab + +// cafe : 2015-02-11 Binky Moon, LLC +cafe + +// cal : 2014-07-24 Charleston Road Registry Inc. +cal + +// call : 2014-12-18 Amazon Registry Services, Inc. +call + +// calvinklein : 2015-07-30 PVH gTLD Holdings LLC +calvinklein + +// cam : 2016-04-21 AC Webconnecting Holding B.V. +cam + +// camera : 2013-08-27 Binky Moon, LLC +camera + +// camp : 2013-11-07 Binky Moon, LLC +camp + +// cancerresearch : 2014-05-15 Australian Cancer Research Foundation +cancerresearch + +// canon : 2014-09-12 Canon Inc. +canon + +// capetown : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry +capetown + +// capital : 2014-03-06 Binky Moon, LLC +capital + +// capitalone : 2015-08-06 Capital One Financial Corporation +capitalone + +// car : 2015-01-22 XYZ.COM LLC +car + +// caravan : 2013-12-12 Caravan International, Inc. +caravan + +// cards : 2013-12-05 Binky Moon, LLC +cards + +// care : 2014-03-06 Binky Moon, LLC +care + +// career : 2013-10-09 dotCareer LLC +career + +// careers : 2013-10-02 Binky Moon, LLC +careers + +// cars : 2014-11-13 XYZ.COM LLC +cars + +// casa : 2013-11-21 Minds + Machines Group Limited +casa + +// case : 2015-09-03 CNH Industrial N.V. +case + +// caseih : 2015-09-03 CNH Industrial N.V. +caseih + +// cash : 2014-03-06 Binky Moon, LLC +cash + +// casino : 2014-12-18 Binky Moon, LLC +casino + +// catering : 2013-12-05 Binky Moon, LLC +catering + +// catholic : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +catholic + +// cba : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA +cba + +// cbn : 2014-08-22 The Christian Broadcasting Network, Inc. +cbn + +// cbre : 2015-07-02 CBRE, Inc. +cbre + +// cbs : 2015-08-06 CBS Domains Inc. +cbs + +// ceb : 2015-04-09 The Corporate Executive Board Company +ceb + +// center : 2013-11-07 Binky Moon, LLC +center + +// ceo : 2013-11-07 CEOTLD Pty Ltd +ceo + +// cern : 2014-06-05 European Organization for Nuclear Research ("CERN") +cern + +// cfa : 2014-08-28 CFA Institute +cfa + +// cfd : 2014-12-11 DotCFD Registry Limited +cfd + +// chanel : 2015-04-09 Chanel International B.V. +chanel + +// channel : 2014-05-08 Charleston Road Registry Inc. +channel + +// charity : 2018-04-11 Binky Moon, LLC +charity + +// chase : 2015-04-30 JPMorgan Chase Bank, National Association +chase + +// chat : 2014-12-04 Binky Moon, LLC +chat + +// cheap : 2013-11-14 Binky Moon, LLC +cheap + +// chintai : 2015-06-11 CHINTAI Corporation +chintai + +// christmas : 2013-11-21 UNR Corp. +christmas + +// chrome : 2014-07-24 Charleston Road Registry Inc. +chrome + +// church : 2014-02-06 Binky Moon, LLC +church + +// cipriani : 2015-02-19 Hotel Cipriani Srl +cipriani + +// circle : 2014-12-18 Amazon Registry Services, Inc. +circle + +// cisco : 2014-12-22 Cisco Technology, Inc. +cisco + +// citadel : 2015-07-23 Citadel Domain LLC +citadel + +// citi : 2015-07-30 Citigroup Inc. +citi + +// citic : 2014-01-09 CITIC Group Corporation +citic + +// city : 2014-05-29 Binky Moon, LLC +city + +// cityeats : 2014-12-11 Lifestyle Domain Holdings, Inc. +cityeats + +// claims : 2014-03-20 Binky Moon, LLC +claims + +// cleaning : 2013-12-05 Binky Moon, LLC +cleaning + +// click : 2014-06-05 UNR Corp. +click + +// clinic : 2014-03-20 Binky Moon, LLC +clinic + +// clinique : 2015-10-01 The Estée Lauder Companies Inc. +clinique + +// clothing : 2013-08-27 Binky Moon, LLC +clothing + +// cloud : 2015-04-16 Aruba PEC S.p.A. +cloud + +// club : 2013-11-08 .CLUB DOMAINS, LLC +club + +// clubmed : 2015-06-25 Club Méditerranée S.A. +clubmed + +// coach : 2014-10-09 Binky Moon, LLC +coach + +// codes : 2013-10-31 Binky Moon, LLC +codes + +// coffee : 2013-10-17 Binky Moon, LLC +coffee + +// college : 2014-01-16 XYZ.COM LLC +college + +// cologne : 2014-02-05 dotKoeln GmbH +cologne + +// comcast : 2015-07-23 Comcast IP Holdings I, LLC +comcast + +// commbank : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA +commbank + +// community : 2013-12-05 Binky Moon, LLC +community + +// company : 2013-11-07 Binky Moon, LLC +company + +// compare : 2015-10-08 Registry Services, LLC +compare + +// computer : 2013-10-24 Binky Moon, LLC +computer + +// comsec : 2015-01-08 VeriSign, Inc. +comsec + +// condos : 2013-12-05 Binky Moon, LLC +condos + +// construction : 2013-09-16 Binky Moon, LLC +construction + +// consulting : 2013-12-05 Dog Beach, LLC +consulting + +// contact : 2015-01-08 Dog Beach, LLC +contact + +// contractors : 2013-09-10 Binky Moon, LLC +contractors + +// cooking : 2013-11-21 Minds + Machines Group Limited +cooking + +// cookingchannel : 2015-07-02 Lifestyle Domain Holdings, Inc. +cookingchannel + +// cool : 2013-11-14 Binky Moon, LLC +cool + +// corsica : 2014-09-25 Collectivité de Corse +corsica + +// country : 2013-12-19 DotCountry LLC +country + +// coupon : 2015-02-26 Amazon Registry Services, Inc. +coupon + +// coupons : 2015-03-26 Binky Moon, LLC +coupons + +// courses : 2014-12-04 OPEN UNIVERSITIES AUSTRALIA PTY LTD +courses + +// cpa : 2019-06-10 American Institute of Certified Public Accountants +cpa + +// credit : 2014-03-20 Binky Moon, LLC +credit + +// creditcard : 2014-03-20 Binky Moon, LLC +creditcard + +// creditunion : 2015-01-22 CUNA Performance Resources, LLC +creditunion + +// cricket : 2014-10-09 dot Cricket Limited +cricket + +// crown : 2014-10-24 Crown Equipment Corporation +crown + +// crs : 2014-04-03 Federated Co-operatives Limited +crs + +// cruise : 2015-12-10 Viking River Cruises (Bermuda) Ltd. +cruise + +// cruises : 2013-12-05 Binky Moon, LLC +cruises + +// csc : 2014-09-25 Alliance-One Services, Inc. +csc + +// cuisinella : 2014-04-03 SCHMIDT GROUPE S.A.S. +cuisinella + +// cymru : 2014-05-08 Nominet UK +cymru + +// cyou : 2015-01-22 ShortDot SA +cyou + +// dabur : 2014-02-06 Dabur India Limited +dabur + +// dad : 2014-01-23 Charleston Road Registry Inc. +dad + +// dance : 2013-10-24 Dog Beach, LLC +dance + +// data : 2016-06-02 Dish DBS Corporation +data + +// date : 2014-11-20 dot Date Limited +date + +// dating : 2013-12-05 Binky Moon, LLC +dating + +// datsun : 2014-03-27 NISSAN MOTOR CO., LTD. +datsun + +// day : 2014-01-30 Charleston Road Registry Inc. +day + +// dclk : 2014-11-20 Charleston Road Registry Inc. +dclk + +// dds : 2015-05-07 Minds + Machines Group Limited +dds + +// deal : 2015-06-25 Amazon Registry Services, Inc. +deal + +// dealer : 2014-12-22 Intercap Registry Inc. +dealer + +// deals : 2014-05-22 Binky Moon, LLC +deals + +// degree : 2014-03-06 Dog Beach, LLC +degree + +// delivery : 2014-09-11 Binky Moon, LLC +delivery + +// dell : 2014-10-24 Dell Inc. +dell + +// deloitte : 2015-07-31 Deloitte Touche Tohmatsu +deloitte + +// delta : 2015-02-19 Delta Air Lines, Inc. +delta + +// democrat : 2013-10-24 Dog Beach, LLC +democrat + +// dental : 2014-03-20 Binky Moon, LLC +dental + +// dentist : 2014-03-20 Dog Beach, LLC +dentist + +// desi : 2013-11-14 Desi Networks LLC +desi + +// design : 2014-11-07 Top Level Design, LLC +design + +// dev : 2014-10-16 Charleston Road Registry Inc. +dev + +// dhl : 2015-07-23 Deutsche Post AG +dhl + +// diamonds : 2013-09-22 Binky Moon, LLC +diamonds + +// diet : 2014-06-26 UNR Corp. +diet + +// digital : 2014-03-06 Binky Moon, LLC +digital + +// direct : 2014-04-10 Binky Moon, LLC +direct + +// directory : 2013-09-20 Binky Moon, LLC +directory + +// discount : 2014-03-06 Binky Moon, LLC +discount + +// discover : 2015-07-23 Discover Financial Services +discover + +// dish : 2015-07-30 Dish DBS Corporation +dish + +// diy : 2015-11-05 Lifestyle Domain Holdings, Inc. +diy + +// dnp : 2013-12-13 Dai Nippon Printing Co., Ltd. +dnp + +// docs : 2014-10-16 Charleston Road Registry Inc. +docs + +// doctor : 2016-06-02 Binky Moon, LLC +doctor + +// dog : 2014-12-04 Binky Moon, LLC +dog + +// domains : 2013-10-17 Binky Moon, LLC +domains + +// dot : 2015-05-21 Dish DBS Corporation +dot + +// download : 2014-11-20 dot Support Limited +download + +// drive : 2015-03-05 Charleston Road Registry Inc. +drive + +// dtv : 2015-06-04 Dish DBS Corporation +dtv + +// dubai : 2015-01-01 Dubai Smart Government Department +dubai + +// duck : 2015-07-23 Johnson Shareholdings, Inc. +duck + +// dunlop : 2015-07-02 The Goodyear Tire & Rubber Company +dunlop + +// dupont : 2015-06-25 E. I. du Pont de Nemours and Company +dupont + +// durban : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry +durban + +// dvag : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG +dvag + +// dvr : 2016-05-26 DISH Technologies L.L.C. +dvr + +// earth : 2014-12-04 Interlink Co., Ltd. +earth + +// eat : 2014-01-23 Charleston Road Registry Inc. +eat + +// eco : 2016-07-08 Big Room Inc. +eco + +// edeka : 2014-12-18 EDEKA Verband kaufmännischer Genossenschaften e.V. +edeka + +// education : 2013-11-07 Binky Moon, LLC +education + +// email : 2013-10-31 Binky Moon, LLC +email + +// emerck : 2014-04-03 Merck KGaA +emerck + +// energy : 2014-09-11 Binky Moon, LLC +energy + +// engineer : 2014-03-06 Dog Beach, LLC +engineer + +// engineering : 2014-03-06 Binky Moon, LLC +engineering + +// enterprises : 2013-09-20 Binky Moon, LLC +enterprises + +// epson : 2014-12-04 Seiko Epson Corporation +epson + +// equipment : 2013-08-27 Binky Moon, LLC +equipment + +// ericsson : 2015-07-09 Telefonaktiebolaget L M Ericsson +ericsson + +// erni : 2014-04-03 ERNI Group Holding AG +erni + +// esq : 2014-05-08 Charleston Road Registry Inc. +esq + +// estate : 2013-08-27 Binky Moon, LLC +estate + +// etisalat : 2015-09-03 Emirates Telecommunications Corporation (trading as Etisalat) +etisalat + +// eurovision : 2014-04-24 European Broadcasting Union (EBU) +eurovision + +// eus : 2013-12-12 Puntueus Fundazioa +eus + +// events : 2013-12-05 Binky Moon, LLC +events + +// exchange : 2014-03-06 Binky Moon, LLC +exchange + +// expert : 2013-11-21 Binky Moon, LLC +expert + +// exposed : 2013-12-05 Binky Moon, LLC +exposed + +// express : 2015-02-11 Binky Moon, LLC +express + +// extraspace : 2015-05-14 Extra Space Storage LLC +extraspace + +// fage : 2014-12-18 Fage International S.A. +fage + +// fail : 2014-03-06 Binky Moon, LLC +fail + +// fairwinds : 2014-11-13 FairWinds Partners, LLC +fairwinds + +// faith : 2014-11-20 dot Faith Limited +faith + +// family : 2015-04-02 Dog Beach, LLC +family + +// fan : 2014-03-06 Dog Beach, LLC +fan + +// fans : 2014-11-07 ZDNS International Limited +fans + +// farm : 2013-11-07 Binky Moon, LLC +farm + +// farmers : 2015-07-09 Farmers Insurance Exchange +farmers + +// fashion : 2014-07-03 Minds + Machines Group Limited +fashion + +// fast : 2014-12-18 Amazon Registry Services, Inc. +fast + +// fedex : 2015-08-06 Federal Express Corporation +fedex + +// feedback : 2013-12-19 Top Level Spectrum, Inc. +feedback + +// ferrari : 2015-07-31 Fiat Chrysler Automobiles N.V. +ferrari + +// ferrero : 2014-12-18 Ferrero Trading Lux S.A. +ferrero + +// fiat : 2015-07-31 Fiat Chrysler Automobiles N.V. +fiat + +// fidelity : 2015-07-30 Fidelity Brokerage Services LLC +fidelity + +// fido : 2015-08-06 Rogers Communications Canada Inc. +fido + +// film : 2015-01-08 Motion Picture Domain Registry Pty Ltd +film + +// final : 2014-10-16 Núcleo de Informação e Coordenação do Ponto BR - NIC.br +final + +// finance : 2014-03-20 Binky Moon, LLC +finance + +// financial : 2014-03-06 Binky Moon, LLC +financial + +// fire : 2015-06-25 Amazon Registry Services, Inc. +fire + +// firestone : 2014-12-18 Bridgestone Licensing Services, Inc +firestone + +// firmdale : 2014-03-27 Firmdale Holdings Limited +firmdale + +// fish : 2013-12-12 Binky Moon, LLC +fish + +// fishing : 2013-11-21 Minds + Machines Group Limited +fishing + +// fit : 2014-11-07 Minds + Machines Group Limited +fit + +// fitness : 2014-03-06 Binky Moon, LLC +fitness + +// flickr : 2015-04-02 Flickr, Inc. +flickr + +// flights : 2013-12-05 Binky Moon, LLC +flights + +// flir : 2015-07-23 FLIR Systems, Inc. +flir + +// florist : 2013-11-07 Binky Moon, LLC +florist + +// flowers : 2014-10-09 UNR Corp. +flowers + +// fly : 2014-05-08 Charleston Road Registry Inc. +fly + +// foo : 2014-01-23 Charleston Road Registry Inc. +foo + +// food : 2016-04-21 Lifestyle Domain Holdings, Inc. +food + +// foodnetwork : 2015-07-02 Lifestyle Domain Holdings, Inc. +foodnetwork + +// football : 2014-12-18 Binky Moon, LLC +football + +// ford : 2014-11-13 Ford Motor Company +ford + +// forex : 2014-12-11 Dotforex Registry Limited +forex + +// forsale : 2014-05-22 Dog Beach, LLC +forsale + +// forum : 2015-04-02 Fegistry, LLC +forum + +// foundation : 2013-12-05 Binky Moon, LLC +foundation + +// fox : 2015-09-11 FOX Registry, LLC +fox + +// free : 2015-12-10 Amazon Registry Services, Inc. +free + +// fresenius : 2015-07-30 Fresenius Immobilien-Verwaltungs-GmbH +fresenius + +// frl : 2014-05-15 FRLregistry B.V. +frl + +// frogans : 2013-12-19 OP3FT +frogans + +// frontdoor : 2015-07-02 Lifestyle Domain Holdings, Inc. +frontdoor + +// frontier : 2015-02-05 Frontier Communications Corporation +frontier + +// ftr : 2015-07-16 Frontier Communications Corporation +ftr + +// fujitsu : 2015-07-30 Fujitsu Limited +fujitsu + +// fujixerox : 2015-07-23 Xerox DNHC LLC +fujixerox + +// fun : 2016-01-14 DotSpace Inc. +fun + +// fund : 2014-03-20 Binky Moon, LLC +fund + +// furniture : 2014-03-20 Binky Moon, LLC +furniture + +// futbol : 2013-09-20 Dog Beach, LLC +futbol + +// fyi : 2015-04-02 Binky Moon, LLC +fyi + +// gal : 2013-11-07 Asociación puntoGAL +gal + +// gallery : 2013-09-13 Binky Moon, LLC +gallery + +// gallo : 2015-06-11 Gallo Vineyards, Inc. +gallo + +// gallup : 2015-02-19 Gallup, Inc. +gallup + +// game : 2015-05-28 UNR Corp. +game + +// games : 2015-05-28 Dog Beach, LLC +games + +// gap : 2015-07-31 The Gap, Inc. +gap + +// garden : 2014-06-26 Minds + Machines Group Limited +garden + +// gay : 2019-05-23 Top Level Design, LLC +gay + +// gbiz : 2014-07-17 Charleston Road Registry Inc. +gbiz + +// gdn : 2014-07-31 Joint Stock Company "Navigation-information systems" +gdn + +// gea : 2014-12-04 GEA Group Aktiengesellschaft +gea + +// gent : 2014-01-23 COMBELL NV +gent + +// genting : 2015-03-12 Resorts World Inc Pte. Ltd. +genting + +// george : 2015-07-31 Wal-Mart Stores, Inc. +george + +// ggee : 2014-01-09 GMO Internet, Inc. +ggee + +// gift : 2013-10-17 DotGift, LLC +gift + +// gifts : 2014-07-03 Binky Moon, LLC +gifts + +// gives : 2014-03-06 Dog Beach, LLC +gives + +// giving : 2014-11-13 Giving Limited +giving + +// glade : 2015-07-23 Johnson Shareholdings, Inc. +glade + +// glass : 2013-11-07 Binky Moon, LLC +glass + +// gle : 2014-07-24 Charleston Road Registry Inc. +gle + +// global : 2014-04-17 Dot Global Domain Registry Limited +global + +// globo : 2013-12-19 Globo Comunicação e Participações S.A +globo + +// gmail : 2014-05-01 Charleston Road Registry Inc. +gmail + +// gmbh : 2016-01-29 Binky Moon, LLC +gmbh + +// gmo : 2014-01-09 GMO Internet, Inc. +gmo + +// gmx : 2014-04-24 1&1 Mail & Media GmbH +gmx + +// godaddy : 2015-07-23 Go Daddy East, LLC +godaddy + +// gold : 2015-01-22 Binky Moon, LLC +gold + +// goldpoint : 2014-11-20 YODOBASHI CAMERA CO.,LTD. +goldpoint + +// golf : 2014-12-18 Binky Moon, LLC +golf + +// goo : 2014-12-18 NTT Resonant Inc. +goo + +// goodyear : 2015-07-02 The Goodyear Tire & Rubber Company +goodyear + +// goog : 2014-11-20 Charleston Road Registry Inc. +goog + +// google : 2014-07-24 Charleston Road Registry Inc. +google + +// gop : 2014-01-16 Republican State Leadership Committee, Inc. +gop + +// got : 2014-12-18 Amazon Registry Services, Inc. +got + +// grainger : 2015-05-07 Grainger Registry Services, LLC +grainger + +// graphics : 2013-09-13 Binky Moon, LLC +graphics + +// gratis : 2014-03-20 Binky Moon, LLC +gratis + +// green : 2014-05-08 Afilias Limited +green + +// gripe : 2014-03-06 Binky Moon, LLC +gripe + +// grocery : 2016-06-16 Wal-Mart Stores, Inc. +grocery + +// group : 2014-08-15 Binky Moon, LLC +group + +// guardian : 2015-07-30 The Guardian Life Insurance Company of America +guardian + +// gucci : 2014-11-13 Guccio Gucci S.p.a. +gucci + +// guge : 2014-08-28 Charleston Road Registry Inc. +guge + +// guide : 2013-09-13 Binky Moon, LLC +guide + +// guitars : 2013-11-14 UNR Corp. +guitars + +// guru : 2013-08-27 Binky Moon, LLC +guru + +// hair : 2015-12-03 XYZ.COM LLC +hair + +// hamburg : 2014-02-20 Hamburg Top-Level-Domain GmbH +hamburg + +// hangout : 2014-11-13 Charleston Road Registry Inc. +hangout + +// haus : 2013-12-05 Dog Beach, LLC +haus + +// hbo : 2015-07-30 HBO Registry Services, Inc. +hbo + +// hdfc : 2015-07-30 HOUSING DEVELOPMENT FINANCE CORPORATION LIMITED +hdfc + +// hdfcbank : 2015-02-12 HDFC Bank Limited +hdfcbank + +// health : 2015-02-11 DotHealth, LLC +health + +// healthcare : 2014-06-12 Binky Moon, LLC +healthcare + +// help : 2014-06-26 UNR Corp. +help + +// helsinki : 2015-02-05 City of Helsinki +helsinki + +// here : 2014-02-06 Charleston Road Registry Inc. +here + +// hermes : 2014-07-10 HERMES INTERNATIONAL +hermes + +// hgtv : 2015-07-02 Lifestyle Domain Holdings, Inc. +hgtv + +// hiphop : 2014-03-06 UNR Corp. +hiphop + +// hisamitsu : 2015-07-16 Hisamitsu Pharmaceutical Co.,Inc. +hisamitsu + +// hitachi : 2014-10-31 Hitachi, Ltd. +hitachi + +// hiv : 2014-03-13 UNR Corp. +hiv + +// hkt : 2015-05-14 PCCW-HKT DataCom Services Limited +hkt + +// hockey : 2015-03-19 Binky Moon, LLC +hockey + +// holdings : 2013-08-27 Binky Moon, LLC +holdings + +// holiday : 2013-11-07 Binky Moon, LLC +holiday + +// homedepot : 2015-04-02 Home Depot Product Authority, LLC +homedepot + +// homegoods : 2015-07-16 The TJX Companies, Inc. +homegoods + +// homes : 2014-01-09 XYZ.COM LLC +homes + +// homesense : 2015-07-16 The TJX Companies, Inc. +homesense + +// honda : 2014-12-18 Honda Motor Co., Ltd. +honda + +// horse : 2013-11-21 Minds + Machines Group Limited +horse + +// hospital : 2016-10-20 Binky Moon, LLC +hospital + +// host : 2014-04-17 DotHost Inc. +host + +// hosting : 2014-05-29 UNR Corp. +hosting + +// hot : 2015-08-27 Amazon Registry Services, Inc. +hot + +// hoteles : 2015-03-05 Travel Reservations SRL +hoteles + +// hotels : 2016-04-07 Booking.com B.V. +hotels + +// hotmail : 2014-12-18 Microsoft Corporation +hotmail + +// house : 2013-11-07 Binky Moon, LLC +house + +// how : 2014-01-23 Charleston Road Registry Inc. +how + +// hsbc : 2014-10-24 HSBC Global Services (UK) Limited +hsbc + +// hughes : 2015-07-30 Hughes Satellite Systems Corporation +hughes + +// hyatt : 2015-07-30 Hyatt GTLD, L.L.C. +hyatt + +// hyundai : 2015-07-09 Hyundai Motor Company +hyundai + +// ibm : 2014-07-31 International Business Machines Corporation +ibm + +// icbc : 2015-02-19 Industrial and Commercial Bank of China Limited +icbc + +// ice : 2014-10-30 IntercontinentalExchange, Inc. +ice + +// icu : 2015-01-08 ShortDot SA +icu + +// ieee : 2015-07-23 IEEE Global LLC +ieee + +// ifm : 2014-01-30 ifm electronic gmbh +ifm + +// ikano : 2015-07-09 Ikano S.A. +ikano + +// imamat : 2015-08-06 Fondation Aga Khan (Aga Khan Foundation) +imamat + +// imdb : 2015-06-25 Amazon Registry Services, Inc. +imdb + +// immo : 2014-07-10 Binky Moon, LLC +immo + +// immobilien : 2013-11-07 Dog Beach, LLC +immobilien + +// inc : 2018-03-10 Intercap Registry Inc. +inc + +// industries : 2013-12-05 Binky Moon, LLC +industries + +// infiniti : 2014-03-27 NISSAN MOTOR CO., LTD. +infiniti + +// ing : 2014-01-23 Charleston Road Registry Inc. +ing + +// ink : 2013-12-05 Top Level Design, LLC +ink + +// institute : 2013-11-07 Binky Moon, LLC +institute + +// insurance : 2015-02-19 fTLD Registry Services LLC +insurance + +// insure : 2014-03-20 Binky Moon, LLC +insure + +// international : 2013-11-07 Binky Moon, LLC +international + +// intuit : 2015-07-30 Intuit Administrative Services, Inc. +intuit + +// investments : 2014-03-20 Binky Moon, LLC +investments + +// ipiranga : 2014-08-28 Ipiranga Produtos de Petroleo S.A. +ipiranga + +// irish : 2014-08-07 Binky Moon, LLC +irish + +// ismaili : 2015-08-06 Fondation Aga Khan (Aga Khan Foundation) +ismaili + +// ist : 2014-08-28 Istanbul Metropolitan Municipality +ist + +// istanbul : 2014-08-28 Istanbul Metropolitan Municipality +istanbul + +// itau : 2014-10-02 Itau Unibanco Holding S.A. +itau + +// itv : 2015-07-09 ITV Services Limited +itv + +// iveco : 2015-09-03 CNH Industrial N.V. +iveco + +// jaguar : 2014-11-13 Jaguar Land Rover Ltd +jaguar + +// java : 2014-06-19 Oracle Corporation +java + +// jcb : 2014-11-20 JCB Co., Ltd. +jcb + +// jeep : 2015-07-30 FCA US LLC. +jeep + +// jetzt : 2014-01-09 Binky Moon, LLC +jetzt + +// jewelry : 2015-03-05 Binky Moon, LLC +jewelry + +// jio : 2015-04-02 Reliance Industries Limited +jio + +// jll : 2015-04-02 Jones Lang LaSalle Incorporated +jll + +// jmp : 2015-03-26 Matrix IP LLC +jmp + +// jnj : 2015-06-18 Johnson & Johnson Services, Inc. +jnj + +// joburg : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry +joburg + +// jot : 2014-12-18 Amazon Registry Services, Inc. +jot + +// joy : 2014-12-18 Amazon Registry Services, Inc. +joy + +// jpmorgan : 2015-04-30 JPMorgan Chase Bank, National Association +jpmorgan + +// jprs : 2014-09-18 Japan Registry Services Co., Ltd. +jprs + +// juegos : 2014-03-20 UNR Corp. +juegos + +// juniper : 2015-07-30 JUNIPER NETWORKS, INC. +juniper + +// kaufen : 2013-11-07 Dog Beach, LLC +kaufen + +// kddi : 2014-09-12 KDDI CORPORATION +kddi + +// kerryhotels : 2015-04-30 Kerry Trading Co. Limited +kerryhotels + +// kerrylogistics : 2015-04-09 Kerry Trading Co. Limited +kerrylogistics + +// kerryproperties : 2015-04-09 Kerry Trading Co. Limited +kerryproperties + +// kfh : 2014-12-04 Kuwait Finance House +kfh + +// kia : 2015-07-09 KIA MOTORS CORPORATION +kia + +// kim : 2013-09-23 Afilias Limited +kim + +// kinder : 2014-11-07 Ferrero Trading Lux S.A. +kinder + +// kindle : 2015-06-25 Amazon Registry Services, Inc. +kindle + +// kitchen : 2013-09-20 Binky Moon, LLC +kitchen + +// kiwi : 2013-09-20 DOT KIWI LIMITED +kiwi + +// koeln : 2014-01-09 dotKoeln GmbH +koeln + +// komatsu : 2015-01-08 Komatsu Ltd. +komatsu + +// kosher : 2015-08-20 Kosher Marketing Assets LLC +kosher + +// kpmg : 2015-04-23 KPMG International Cooperative (KPMG International Genossenschaft) +kpmg + +// kpn : 2015-01-08 Koninklijke KPN N.V. +kpn + +// krd : 2013-12-05 KRG Department of Information Technology +krd + +// kred : 2013-12-19 KredTLD Pty Ltd +kred + +// kuokgroup : 2015-04-09 Kerry Trading Co. Limited +kuokgroup + +// kyoto : 2014-11-07 Academic Institution: Kyoto Jyoho Gakuen +kyoto + +// lacaixa : 2014-01-09 Fundación Bancaria Caixa d’Estalvis i Pensions de Barcelona, “la Caixa” +lacaixa + +// lamborghini : 2015-06-04 Automobili Lamborghini S.p.A. +lamborghini + +// lamer : 2015-10-01 The Estée Lauder Companies Inc. +lamer + +// lancaster : 2015-02-12 LANCASTER +lancaster + +// lancia : 2015-07-31 Fiat Chrysler Automobiles N.V. +lancia + +// land : 2013-09-10 Binky Moon, LLC +land + +// landrover : 2014-11-13 Jaguar Land Rover Ltd +landrover + +// lanxess : 2015-07-30 LANXESS Corporation +lanxess + +// lasalle : 2015-04-02 Jones Lang LaSalle Incorporated +lasalle + +// lat : 2014-10-16 ECOM-LAC Federaciòn de Latinoamèrica y el Caribe para Internet y el Comercio Electrònico +lat + +// latino : 2015-07-30 Dish DBS Corporation +latino + +// latrobe : 2014-06-16 La Trobe University +latrobe + +// law : 2015-01-22 LW TLD Limited +law + +// lawyer : 2014-03-20 Dog Beach, LLC +lawyer + +// lds : 2014-03-20 IRI Domain Management, LLC +lds + +// lease : 2014-03-06 Binky Moon, LLC +lease + +// leclerc : 2014-08-07 A.C.D. LEC Association des Centres Distributeurs Edouard Leclerc +leclerc + +// lefrak : 2015-07-16 LeFrak Organization, Inc. +lefrak + +// legal : 2014-10-16 Binky Moon, LLC +legal + +// lego : 2015-07-16 LEGO Juris A/S +lego + +// lexus : 2015-04-23 TOYOTA MOTOR CORPORATION +lexus + +// lgbt : 2014-05-08 Afilias Limited +lgbt + +// lidl : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG +lidl + +// life : 2014-02-06 Binky Moon, LLC +life + +// lifeinsurance : 2015-01-15 American Council of Life Insurers +lifeinsurance + +// lifestyle : 2014-12-11 Lifestyle Domain Holdings, Inc. +lifestyle + +// lighting : 2013-08-27 Binky Moon, LLC +lighting + +// like : 2014-12-18 Amazon Registry Services, Inc. +like + +// lilly : 2015-07-31 Eli Lilly and Company +lilly + +// limited : 2014-03-06 Binky Moon, LLC +limited + +// limo : 2013-10-17 Binky Moon, LLC +limo + +// lincoln : 2014-11-13 Ford Motor Company +lincoln + +// linde : 2014-12-04 Linde Aktiengesellschaft +linde + +// link : 2013-11-14 UNR Corp. +link + +// lipsy : 2015-06-25 Lipsy Ltd +lipsy + +// live : 2014-12-04 Dog Beach, LLC +live + +// living : 2015-07-30 Lifestyle Domain Holdings, Inc. +living + +// lixil : 2015-03-19 LIXIL Group Corporation +lixil + +// llc : 2017-12-14 Afilias Limited +llc + +// llp : 2019-08-26 UNR Corp. +llp + +// loan : 2014-11-20 dot Loan Limited +loan + +// loans : 2014-03-20 Binky Moon, LLC +loans + +// locker : 2015-06-04 Dish DBS Corporation +locker + +// locus : 2015-06-25 Locus Analytics LLC +locus + +// loft : 2015-07-30 Annco, Inc. +loft + +// lol : 2015-01-30 UNR Corp. +lol + +// london : 2013-11-14 Dot London Domains Limited +london + +// lotte : 2014-11-07 Lotte Holdings Co., Ltd. +lotte + +// lotto : 2014-04-10 Afilias Limited +lotto + +// love : 2014-12-22 Merchant Law Group LLP +love + +// lpl : 2015-07-30 LPL Holdings, Inc. +lpl + +// lplfinancial : 2015-07-30 LPL Holdings, Inc. +lplfinancial + +// ltd : 2014-09-25 Binky Moon, LLC +ltd + +// ltda : 2014-04-17 InterNetX, Corp +ltda + +// lundbeck : 2015-08-06 H. Lundbeck A/S +lundbeck + +// lupin : 2014-11-07 LUPIN LIMITED +lupin + +// luxe : 2014-01-09 Minds + Machines Group Limited +luxe + +// luxury : 2013-10-17 Luxury Partners, LLC +luxury + +// macys : 2015-07-31 Macys, Inc. +macys + +// madrid : 2014-05-01 Comunidad de Madrid +madrid + +// maif : 2014-10-02 Mutuelle Assurance Instituteur France (MAIF) +maif + +// maison : 2013-12-05 Binky Moon, LLC +maison + +// makeup : 2015-01-15 XYZ.COM LLC +makeup + +// man : 2014-12-04 MAN SE +man + +// management : 2013-11-07 Binky Moon, LLC +management + +// mango : 2013-10-24 PUNTO FA S.L. +mango + +// map : 2016-06-09 Charleston Road Registry Inc. +map + +// market : 2014-03-06 Dog Beach, LLC +market + +// marketing : 2013-11-07 Binky Moon, LLC +marketing + +// markets : 2014-12-11 Dotmarkets Registry Limited +markets + +// marriott : 2014-10-09 Marriott Worldwide Corporation +marriott + +// marshalls : 2015-07-16 The TJX Companies, Inc. +marshalls + +// maserati : 2015-07-31 Fiat Chrysler Automobiles N.V. +maserati + +// mattel : 2015-08-06 Mattel Sites, Inc. +mattel + +// mba : 2015-04-02 Binky Moon, LLC +mba + +// mckinsey : 2015-07-31 McKinsey Holdings, Inc. +mckinsey + +// med : 2015-08-06 Medistry LLC +med + +// media : 2014-03-06 Binky Moon, LLC +media + +// meet : 2014-01-16 Charleston Road Registry Inc. +meet + +// melbourne : 2014-05-29 The Crown in right of the State of Victoria, represented by its Department of State Development, Business and Innovation +melbourne + +// meme : 2014-01-30 Charleston Road Registry Inc. +meme + +// memorial : 2014-10-16 Dog Beach, LLC +memorial + +// men : 2015-02-26 Exclusive Registry Limited +men + +// menu : 2013-09-11 Dot Menu Registry, LLC +menu + +// merckmsd : 2016-07-14 MSD Registry Holdings, Inc. +merckmsd + +// miami : 2013-12-19 Minds + Machines Group Limited +miami + +// microsoft : 2014-12-18 Microsoft Corporation +microsoft + +// mini : 2014-01-09 Bayerische Motoren Werke Aktiengesellschaft +mini + +// mint : 2015-07-30 Intuit Administrative Services, Inc. +mint + +// mit : 2015-07-02 Massachusetts Institute of Technology +mit + +// mitsubishi : 2015-07-23 Mitsubishi Corporation +mitsubishi + +// mlb : 2015-05-21 MLB Advanced Media DH, LLC +mlb + +// mls : 2015-04-23 The Canadian Real Estate Association +mls + +// mma : 2014-11-07 MMA IARD +mma + +// mobile : 2016-06-02 Dish DBS Corporation +mobile + +// moda : 2013-11-07 Dog Beach, LLC +moda + +// moe : 2013-11-13 Interlink Co., Ltd. +moe + +// moi : 2014-12-18 Amazon Registry Services, Inc. +moi + +// mom : 2015-04-16 UNR Corp. +mom + +// monash : 2013-09-30 Monash University +monash + +// money : 2014-10-16 Binky Moon, LLC +money + +// monster : 2015-09-11 XYZ.COM LLC +monster + +// mormon : 2013-12-05 IRI Domain Management, LLC +mormon + +// mortgage : 2014-03-20 Dog Beach, LLC +mortgage + +// moscow : 2013-12-19 Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID) +moscow + +// moto : 2015-06-04 Motorola Trademark Holdings, LLC +moto + +// motorcycles : 2014-01-09 XYZ.COM LLC +motorcycles + +// mov : 2014-01-30 Charleston Road Registry Inc. +mov + +// movie : 2015-02-05 Binky Moon, LLC +movie + +// msd : 2015-07-23 MSD Registry Holdings, Inc. +msd + +// mtn : 2014-12-04 MTN Dubai Limited +mtn + +// mtr : 2015-03-12 MTR Corporation Limited +mtr + +// mutual : 2015-04-02 Northwestern Mutual MU TLD Registry, LLC +mutual + +// nab : 2015-08-20 National Australia Bank Limited +nab + +// nagoya : 2013-10-24 GMO Registry, Inc. +nagoya + +// nationwide : 2015-07-23 Nationwide Mutual Insurance Company +nationwide + +// natura : 2015-03-12 NATURA COSMÉTICOS S.A. +natura + +// navy : 2014-03-06 Dog Beach, LLC +navy + +// nba : 2015-07-31 NBA REGISTRY, LLC +nba + +// nec : 2015-01-08 NEC Corporation +nec + +// netbank : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA +netbank + +// netflix : 2015-06-18 Netflix, Inc. +netflix + +// network : 2013-11-14 Binky Moon, LLC +network + +// neustar : 2013-12-05 NeuStar, Inc. +neustar + +// new : 2014-01-30 Charleston Road Registry Inc. +new + +// newholland : 2015-09-03 CNH Industrial N.V. +newholland + +// news : 2014-12-18 Dog Beach, LLC +news + +// next : 2015-06-18 Next plc +next + +// nextdirect : 2015-06-18 Next plc +nextdirect + +// nexus : 2014-07-24 Charleston Road Registry Inc. +nexus + +// nfl : 2015-07-23 NFL Reg Ops LLC +nfl + +// ngo : 2014-03-06 Public Interest Registry +ngo + +// nhk : 2014-02-13 Japan Broadcasting Corporation (NHK) +nhk + +// nico : 2014-12-04 DWANGO Co., Ltd. +nico + +// nike : 2015-07-23 NIKE, Inc. +nike + +// nikon : 2015-05-21 NIKON CORPORATION +nikon + +// ninja : 2013-11-07 Dog Beach, LLC +ninja + +// nissan : 2014-03-27 NISSAN MOTOR CO., LTD. +nissan + +// nissay : 2015-10-29 Nippon Life Insurance Company +nissay + +// nokia : 2015-01-08 Nokia Corporation +nokia + +// northwesternmutual : 2015-06-18 Northwestern Mutual Registry, LLC +northwesternmutual + +// norton : 2014-12-04 NortonLifeLock Inc. +norton + +// now : 2015-06-25 Amazon Registry Services, Inc. +now + +// nowruz : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +nowruz + +// nowtv : 2015-05-14 Starbucks (HK) Limited +nowtv + +// nra : 2014-05-22 NRA Holdings Company, INC. +nra + +// nrw : 2013-11-21 Minds + Machines GmbH +nrw + +// ntt : 2014-10-31 NIPPON TELEGRAPH AND TELEPHONE CORPORATION +ntt + +// nyc : 2014-01-23 The City of New York by and through the New York City Department of Information Technology & Telecommunications +nyc + +// obi : 2014-09-25 OBI Group Holding SE & Co. KGaA +obi + +// observer : 2015-04-30 Top Level Spectrum, Inc. +observer + +// off : 2015-07-23 Johnson Shareholdings, Inc. +off + +// office : 2015-03-12 Microsoft Corporation +office + +// okinawa : 2013-12-05 BRregistry, Inc. +okinawa + +// olayan : 2015-05-14 Crescent Holding GmbH +olayan + +// olayangroup : 2015-05-14 Crescent Holding GmbH +olayangroup + +// oldnavy : 2015-07-31 The Gap, Inc. +oldnavy + +// ollo : 2015-06-04 Dish DBS Corporation +ollo + +// omega : 2015-01-08 The Swatch Group Ltd +omega + +// one : 2014-11-07 One.com A/S +one + +// ong : 2014-03-06 Public Interest Registry +ong + +// onl : 2013-09-16 iRegistry GmbH +onl + +// online : 2015-01-15 DotOnline Inc. +online + +// onyourside : 2015-07-23 Nationwide Mutual Insurance Company +onyourside + +// ooo : 2014-01-09 INFIBEAM AVENUES LIMITED +ooo + +// open : 2015-07-31 American Express Travel Related Services Company, Inc. +open + +// oracle : 2014-06-19 Oracle Corporation +oracle + +// orange : 2015-03-12 Orange Brand Services Limited +orange + +// organic : 2014-03-27 Afilias Limited +organic + +// origins : 2015-10-01 The Estée Lauder Companies Inc. +origins + +// osaka : 2014-09-04 Osaka Registry Co., Ltd. +osaka + +// otsuka : 2013-10-11 Otsuka Holdings Co., Ltd. +otsuka + +// ott : 2015-06-04 Dish DBS Corporation +ott + +// ovh : 2014-01-16 MédiaBC +ovh + +// page : 2014-12-04 Charleston Road Registry Inc. +page + +// panasonic : 2015-07-30 Panasonic Corporation +panasonic + +// paris : 2014-01-30 City of Paris +paris + +// pars : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +pars + +// partners : 2013-12-05 Binky Moon, LLC +partners + +// parts : 2013-12-05 Binky Moon, LLC +parts + +// party : 2014-09-11 Blue Sky Registry Limited +party + +// passagens : 2015-03-05 Travel Reservations SRL +passagens + +// pay : 2015-08-27 Amazon Registry Services, Inc. +pay + +// pccw : 2015-05-14 PCCW Enterprises Limited +pccw + +// pet : 2015-05-07 Afilias Limited +pet + +// pfizer : 2015-09-11 Pfizer Inc. +pfizer + +// pharmacy : 2014-06-19 National Association of Boards of Pharmacy +pharmacy + +// phd : 2016-07-28 Charleston Road Registry Inc. +phd + +// philips : 2014-11-07 Koninklijke Philips N.V. +philips + +// phone : 2016-06-02 Dish DBS Corporation +phone + +// photo : 2013-11-14 UNR Corp. +photo + +// photography : 2013-09-20 Binky Moon, LLC +photography + +// photos : 2013-10-17 Binky Moon, LLC +photos + +// physio : 2014-05-01 PhysBiz Pty Ltd +physio + +// pics : 2013-11-14 UNR Corp. +pics + +// pictet : 2014-06-26 Pictet Europe S.A. +pictet + +// pictures : 2014-03-06 Binky Moon, LLC +pictures + +// pid : 2015-01-08 Top Level Spectrum, Inc. +pid + +// pin : 2014-12-18 Amazon Registry Services, Inc. +pin + +// ping : 2015-06-11 Ping Registry Provider, Inc. +ping + +// pink : 2013-10-01 Afilias Limited +pink + +// pioneer : 2015-07-16 Pioneer Corporation +pioneer + +// pizza : 2014-06-26 Binky Moon, LLC +pizza + +// place : 2014-04-24 Binky Moon, LLC +place + +// play : 2015-03-05 Charleston Road Registry Inc. +play + +// playstation : 2015-07-02 Sony Interactive Entertainment Inc. +playstation + +// plumbing : 2013-09-10 Binky Moon, LLC +plumbing + +// plus : 2015-02-05 Binky Moon, LLC +plus + +// pnc : 2015-07-02 PNC Domain Co., LLC +pnc + +// pohl : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG +pohl + +// poker : 2014-07-03 Afilias Limited +poker + +// politie : 2015-08-20 Politie Nederland +politie + +// porn : 2014-10-16 ICM Registry PN LLC +porn + +// pramerica : 2015-07-30 Prudential Financial, Inc. +pramerica + +// praxi : 2013-12-05 Praxi S.p.A. +praxi + +// press : 2014-04-03 DotPress Inc. +press + +// prime : 2015-06-25 Amazon Registry Services, Inc. +prime + +// prod : 2014-01-23 Charleston Road Registry Inc. +prod + +// productions : 2013-12-05 Binky Moon, LLC +productions + +// prof : 2014-07-24 Charleston Road Registry Inc. +prof + +// progressive : 2015-07-23 Progressive Casualty Insurance Company +progressive + +// promo : 2014-12-18 Afilias Limited +promo + +// properties : 2013-12-05 Binky Moon, LLC +properties + +// property : 2014-05-22 UNR Corp. +property + +// protection : 2015-04-23 XYZ.COM LLC +protection + +// pru : 2015-07-30 Prudential Financial, Inc. +pru + +// prudential : 2015-07-30 Prudential Financial, Inc. +prudential + +// pub : 2013-12-12 Dog Beach, LLC +pub + +// pwc : 2015-10-29 PricewaterhouseCoopers LLP +pwc + +// qpon : 2013-11-14 dotCOOL, Inc. +qpon + +// quebec : 2013-12-19 PointQuébec Inc +quebec + +// quest : 2015-03-26 XYZ.COM LLC +quest + +// qvc : 2015-07-30 QVC, Inc. +qvc + +// racing : 2014-12-04 Premier Registry Limited +racing + +// radio : 2016-07-21 European Broadcasting Union (EBU) +radio + +// raid : 2015-07-23 Johnson Shareholdings, Inc. +raid + +// read : 2014-12-18 Amazon Registry Services, Inc. +read + +// realestate : 2015-09-11 dotRealEstate LLC +realestate + +// realtor : 2014-05-29 Real Estate Domains LLC +realtor + +// realty : 2015-03-19 Fegistry, LLC +realty + +// recipes : 2013-10-17 Binky Moon, LLC +recipes + +// red : 2013-11-07 Afilias Limited +red + +// redstone : 2014-10-31 Redstone Haute Couture Co., Ltd. +redstone + +// redumbrella : 2015-03-26 Travelers TLD, LLC +redumbrella + +// rehab : 2014-03-06 Dog Beach, LLC +rehab + +// reise : 2014-03-13 Binky Moon, LLC +reise + +// reisen : 2014-03-06 Binky Moon, LLC +reisen + +// reit : 2014-09-04 National Association of Real Estate Investment Trusts, Inc. +reit + +// reliance : 2015-04-02 Reliance Industries Limited +reliance + +// ren : 2013-12-12 ZDNS International Limited +ren + +// rent : 2014-12-04 XYZ.COM LLC +rent + +// rentals : 2013-12-05 Binky Moon, LLC +rentals + +// repair : 2013-11-07 Binky Moon, LLC +repair + +// report : 2013-12-05 Binky Moon, LLC +report + +// republican : 2014-03-20 Dog Beach, LLC +republican + +// rest : 2013-12-19 Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable +rest + +// restaurant : 2014-07-03 Binky Moon, LLC +restaurant + +// review : 2014-11-20 dot Review Limited +review + +// reviews : 2013-09-13 Dog Beach, LLC +reviews + +// rexroth : 2015-06-18 Robert Bosch GMBH +rexroth + +// rich : 2013-11-21 iRegistry GmbH +rich + +// richardli : 2015-05-14 Pacific Century Asset Management (HK) Limited +richardli + +// ricoh : 2014-11-20 Ricoh Company, Ltd. +ricoh + +// ril : 2015-04-02 Reliance Industries Limited +ril + +// rio : 2014-02-27 Empresa Municipal de Informática SA - IPLANRIO +rio + +// rip : 2014-07-10 Dog Beach, LLC +rip + +// rmit : 2015-11-19 Royal Melbourne Institute of Technology +rmit + +// rocher : 2014-12-18 Ferrero Trading Lux S.A. +rocher + +// rocks : 2013-11-14 Dog Beach, LLC +rocks + +// rodeo : 2013-12-19 Minds + Machines Group Limited +rodeo + +// rogers : 2015-08-06 Rogers Communications Canada Inc. +rogers + +// room : 2014-12-18 Amazon Registry Services, Inc. +room + +// rsvp : 2014-05-08 Charleston Road Registry Inc. +rsvp + +// rugby : 2016-12-15 World Rugby Strategic Developments Limited +rugby + +// ruhr : 2013-10-02 regiodot GmbH & Co. KG +ruhr + +// run : 2015-03-19 Binky Moon, LLC +run + +// rwe : 2015-04-02 RWE AG +rwe + +// ryukyu : 2014-01-09 BRregistry, Inc. +ryukyu + +// saarland : 2013-12-12 dotSaarland GmbH +saarland + +// safe : 2014-12-18 Amazon Registry Services, Inc. +safe + +// safety : 2015-01-08 Safety Registry Services, LLC. +safety + +// sakura : 2014-12-18 SAKURA Internet Inc. +sakura + +// sale : 2014-10-16 Dog Beach, LLC +sale + +// salon : 2014-12-11 Binky Moon, LLC +salon + +// samsclub : 2015-07-31 Wal-Mart Stores, Inc. +samsclub + +// samsung : 2014-04-03 SAMSUNG SDS CO., LTD +samsung + +// sandvik : 2014-11-13 Sandvik AB +sandvik + +// sandvikcoromant : 2014-11-07 Sandvik AB +sandvikcoromant + +// sanofi : 2014-10-09 Sanofi +sanofi + +// sap : 2014-03-27 SAP AG +sap + +// sarl : 2014-07-03 Binky Moon, LLC +sarl + +// sas : 2015-04-02 Research IP LLC +sas + +// save : 2015-06-25 Amazon Registry Services, Inc. +save + +// saxo : 2014-10-31 Saxo Bank A/S +saxo + +// sbi : 2015-03-12 STATE BANK OF INDIA +sbi + +// sbs : 2014-11-07 SPECIAL BROADCASTING SERVICE CORPORATION +sbs + +// sca : 2014-03-13 SVENSKA CELLULOSA AKTIEBOLAGET SCA (publ) +sca + +// scb : 2014-02-20 The Siam Commercial Bank Public Company Limited ("SCB") +scb + +// schaeffler : 2015-08-06 Schaeffler Technologies AG & Co. KG +schaeffler + +// schmidt : 2014-04-03 SCHMIDT GROUPE S.A.S. +schmidt + +// scholarships : 2014-04-24 Scholarships.com, LLC +scholarships + +// school : 2014-12-18 Binky Moon, LLC +school + +// schule : 2014-03-06 Binky Moon, LLC +schule + +// schwarz : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG +schwarz + +// science : 2014-09-11 dot Science Limited +science + +// scjohnson : 2015-07-23 Johnson Shareholdings, Inc. +scjohnson + +// scot : 2014-01-23 Dot Scot Registry Limited +scot + +// search : 2016-06-09 Charleston Road Registry Inc. +search + +// seat : 2014-05-22 SEAT, S.A. (Sociedad Unipersonal) +seat + +// secure : 2015-08-27 Amazon Registry Services, Inc. +secure + +// security : 2015-05-14 XYZ.COM LLC +security + +// seek : 2014-12-04 Seek Limited +seek + +// select : 2015-10-08 Registry Services, LLC +select + +// sener : 2014-10-24 Sener Ingeniería y Sistemas, S.A. +sener + +// services : 2014-02-27 Binky Moon, LLC +services + +// ses : 2015-07-23 SES +ses + +// seven : 2015-08-06 Seven West Media Ltd +seven + +// sew : 2014-07-17 SEW-EURODRIVE GmbH & Co KG +sew + +// sex : 2014-11-13 ICM Registry SX LLC +sex + +// sexy : 2013-09-11 UNR Corp. +sexy + +// sfr : 2015-08-13 Societe Francaise du Radiotelephone - SFR +sfr + +// shangrila : 2015-09-03 Shangri‐La International Hotel Management Limited +shangrila + +// sharp : 2014-05-01 Sharp Corporation +sharp + +// shaw : 2015-04-23 Shaw Cablesystems G.P. +shaw + +// shell : 2015-07-30 Shell Information Technology International Inc +shell + +// shia : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +shia + +// shiksha : 2013-11-14 Afilias Limited +shiksha + +// shoes : 2013-10-02 Binky Moon, LLC +shoes + +// shop : 2016-04-08 GMO Registry, Inc. +shop + +// shopping : 2016-03-31 Binky Moon, LLC +shopping + +// shouji : 2015-01-08 Beijing Qihu Keji Co., Ltd. +shouji + +// show : 2015-03-05 Binky Moon, LLC +show + +// showtime : 2015-08-06 CBS Domains Inc. +showtime + +// shriram : 2014-01-23 Shriram Capital Ltd. +shriram + +// silk : 2015-06-25 Amazon Registry Services, Inc. +silk + +// sina : 2015-03-12 Sina Corporation +sina + +// singles : 2013-08-27 Binky Moon, LLC +singles + +// site : 2015-01-15 DotSite Inc. +site + +// ski : 2015-04-09 Afilias Limited +ski + +// skin : 2015-01-15 XYZ.COM LLC +skin + +// sky : 2014-06-19 Sky International AG +sky + +// skype : 2014-12-18 Microsoft Corporation +skype + +// sling : 2015-07-30 DISH Technologies L.L.C. +sling + +// smart : 2015-07-09 Smart Communications, Inc. (SMART) +smart + +// smile : 2014-12-18 Amazon Registry Services, Inc. +smile + +// sncf : 2015-02-19 Société Nationale des Chemins de fer Francais S N C F +sncf + +// soccer : 2015-03-26 Binky Moon, LLC +soccer + +// social : 2013-11-07 Dog Beach, LLC +social + +// softbank : 2015-07-02 SoftBank Group Corp. +softbank + +// software : 2014-03-20 Dog Beach, LLC +software + +// sohu : 2013-12-19 Sohu.com Limited +sohu + +// solar : 2013-11-07 Binky Moon, LLC +solar + +// solutions : 2013-11-07 Binky Moon, LLC +solutions + +// song : 2015-02-26 Amazon Registry Services, Inc. +song + +// sony : 2015-01-08 Sony Corporation +sony + +// soy : 2014-01-23 Charleston Road Registry Inc. +soy + +// spa : 2019-09-19 Asia Spa and Wellness Promotion Council Limited +spa + +// space : 2014-04-03 DotSpace Inc. +space + +// sport : 2017-11-16 Global Association of International Sports Federations (GAISF) +sport + +// spot : 2015-02-26 Amazon Registry Services, Inc. +spot + +// spreadbetting : 2014-12-11 Dotspreadbetting Registry Limited +spreadbetting + +// srl : 2015-05-07 InterNetX, Corp +srl + +// stada : 2014-11-13 STADA Arzneimittel AG +stada + +// staples : 2015-07-30 Staples, Inc. +staples + +// star : 2015-01-08 Star India Private Limited +star + +// statebank : 2015-03-12 STATE BANK OF INDIA +statebank + +// statefarm : 2015-07-30 State Farm Mutual Automobile Insurance Company +statefarm + +// stc : 2014-10-09 Saudi Telecom Company +stc + +// stcgroup : 2014-10-09 Saudi Telecom Company +stcgroup + +// stockholm : 2014-12-18 Stockholms kommun +stockholm + +// storage : 2014-12-22 XYZ.COM LLC +storage + +// store : 2015-04-09 DotStore Inc. +store + +// stream : 2016-01-08 dot Stream Limited +stream + +// studio : 2015-02-11 Dog Beach, LLC +studio + +// study : 2014-12-11 OPEN UNIVERSITIES AUSTRALIA PTY LTD +study + +// style : 2014-12-04 Binky Moon, LLC +style + +// sucks : 2014-12-22 Vox Populi Registry Ltd. +sucks + +// supplies : 2013-12-19 Binky Moon, LLC +supplies + +// supply : 2013-12-19 Binky Moon, LLC +supply + +// support : 2013-10-24 Binky Moon, LLC +support + +// surf : 2014-01-09 Minds + Machines Group Limited +surf + +// surgery : 2014-03-20 Binky Moon, LLC +surgery + +// suzuki : 2014-02-20 SUZUKI MOTOR CORPORATION +suzuki + +// swatch : 2015-01-08 The Swatch Group Ltd +swatch + +// swiftcover : 2015-07-23 Swiftcover Insurance Services Limited +swiftcover + +// swiss : 2014-10-16 Swiss Confederation +swiss + +// sydney : 2014-09-18 State of New South Wales, Department of Premier and Cabinet +sydney + +// systems : 2013-11-07 Binky Moon, LLC +systems + +// tab : 2014-12-04 Tabcorp Holdings Limited +tab + +// taipei : 2014-07-10 Taipei City Government +taipei + +// talk : 2015-04-09 Amazon Registry Services, Inc. +talk + +// taobao : 2015-01-15 Alibaba Group Holding Limited +taobao + +// target : 2015-07-31 Target Domain Holdings, LLC +target + +// tatamotors : 2015-03-12 Tata Motors Ltd +tatamotors + +// tatar : 2014-04-24 Limited Liability Company "Coordination Center of Regional Domain of Tatarstan Republic" +tatar + +// tattoo : 2013-08-30 UNR Corp. +tattoo + +// tax : 2014-03-20 Binky Moon, LLC +tax + +// taxi : 2015-03-19 Binky Moon, LLC +taxi + +// tci : 2014-09-12 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +tci + +// tdk : 2015-06-11 TDK Corporation +tdk + +// team : 2015-03-05 Binky Moon, LLC +team + +// tech : 2015-01-30 Personals TLD Inc. +tech + +// technology : 2013-09-13 Binky Moon, LLC +technology + +// temasek : 2014-08-07 Temasek Holdings (Private) Limited +temasek + +// tennis : 2014-12-04 Binky Moon, LLC +tennis + +// teva : 2015-07-02 Teva Pharmaceutical Industries Limited +teva + +// thd : 2015-04-02 Home Depot Product Authority, LLC +thd + +// theater : 2015-03-19 Binky Moon, LLC +theater + +// theatre : 2015-05-07 XYZ.COM LLC +theatre + +// tiaa : 2015-07-23 Teachers Insurance and Annuity Association of America +tiaa + +// tickets : 2015-02-05 Accent Media Limited +tickets + +// tienda : 2013-11-14 Binky Moon, LLC +tienda + +// tiffany : 2015-01-30 Tiffany and Company +tiffany + +// tips : 2013-09-20 Binky Moon, LLC +tips + +// tires : 2014-11-07 Binky Moon, LLC +tires + +// tirol : 2014-04-24 punkt Tirol GmbH +tirol + +// tjmaxx : 2015-07-16 The TJX Companies, Inc. +tjmaxx + +// tjx : 2015-07-16 The TJX Companies, Inc. +tjx + +// tkmaxx : 2015-07-16 The TJX Companies, Inc. +tkmaxx + +// tmall : 2015-01-15 Alibaba Group Holding Limited +tmall + +// today : 2013-09-20 Binky Moon, LLC +today + +// tokyo : 2013-11-13 GMO Registry, Inc. +tokyo + +// tools : 2013-11-21 Binky Moon, LLC +tools + +// top : 2014-03-20 .TOP Registry +top + +// toray : 2014-12-18 Toray Industries, Inc. +toray + +// toshiba : 2014-04-10 TOSHIBA Corporation +toshiba + +// total : 2015-08-06 Total SA +total + +// tours : 2015-01-22 Binky Moon, LLC +tours + +// town : 2014-03-06 Binky Moon, LLC +town + +// toyota : 2015-04-23 TOYOTA MOTOR CORPORATION +toyota + +// toys : 2014-03-06 Binky Moon, LLC +toys + +// trade : 2014-01-23 Elite Registry Limited +trade + +// trading : 2014-12-11 Dottrading Registry Limited +trading + +// training : 2013-11-07 Binky Moon, LLC +training + +// travel : 2015-10-09 Dog Beach, LLC +travel + +// travelchannel : 2015-07-02 Lifestyle Domain Holdings, Inc. +travelchannel + +// travelers : 2015-03-26 Travelers TLD, LLC +travelers + +// travelersinsurance : 2015-03-26 Travelers TLD, LLC +travelersinsurance + +// trust : 2014-10-16 UNR Corp. +trust + +// trv : 2015-03-26 Travelers TLD, LLC +trv + +// tube : 2015-06-11 Latin American Telecom LLC +tube + +// tui : 2014-07-03 TUI AG +tui + +// tunes : 2015-02-26 Amazon Registry Services, Inc. +tunes + +// tushu : 2014-12-18 Amazon Registry Services, Inc. +tushu + +// tvs : 2015-02-19 T V SUNDRAM IYENGAR & SONS LIMITED +tvs + +// ubank : 2015-08-20 National Australia Bank Limited +ubank + +// ubs : 2014-12-11 UBS AG +ubs + +// unicom : 2015-10-15 China United Network Communications Corporation Limited +unicom + +// university : 2014-03-06 Binky Moon, LLC +university + +// uno : 2013-09-11 DotSite Inc. +uno + +// uol : 2014-05-01 UBN INTERNET LTDA. +uol + +// ups : 2015-06-25 UPS Market Driver, Inc. +ups + +// vacations : 2013-12-05 Binky Moon, LLC +vacations + +// vana : 2014-12-11 Lifestyle Domain Holdings, Inc. +vana + +// vanguard : 2015-09-03 The Vanguard Group, Inc. +vanguard + +// vegas : 2014-01-16 Dot Vegas, Inc. +vegas + +// ventures : 2013-08-27 Binky Moon, LLC +ventures + +// verisign : 2015-08-13 VeriSign, Inc. +verisign + +// versicherung : 2014-03-20 tldbox GmbH +versicherung + +// vet : 2014-03-06 Dog Beach, LLC +vet + +// viajes : 2013-10-17 Binky Moon, LLC +viajes + +// video : 2014-10-16 Dog Beach, LLC +video + +// vig : 2015-05-14 VIENNA INSURANCE GROUP AG Wiener Versicherung Gruppe +vig + +// viking : 2015-04-02 Viking River Cruises (Bermuda) Ltd. +viking + +// villas : 2013-12-05 Binky Moon, LLC +villas + +// vin : 2015-06-18 Binky Moon, LLC +vin + +// vip : 2015-01-22 Minds + Machines Group Limited +vip + +// virgin : 2014-09-25 Virgin Enterprises Limited +virgin + +// visa : 2015-07-30 Visa Worldwide Pte. Limited +visa + +// vision : 2013-12-05 Binky Moon, LLC +vision + +// viva : 2014-11-07 Saudi Telecom Company +viva + +// vivo : 2015-07-31 Telefonica Brasil S.A. +vivo + +// vlaanderen : 2014-02-06 DNS.be vzw +vlaanderen + +// vodka : 2013-12-19 Minds + Machines Group Limited +vodka + +// volkswagen : 2015-05-14 Volkswagen Group of America Inc. +volkswagen + +// volvo : 2015-11-12 Volvo Holding Sverige Aktiebolag +volvo + +// vote : 2013-11-21 Monolith Registry LLC +vote + +// voting : 2013-11-13 Valuetainment Corp. +voting + +// voto : 2013-11-21 Monolith Registry LLC +voto + +// voyage : 2013-08-27 Binky Moon, LLC +voyage + +// vuelos : 2015-03-05 Travel Reservations SRL +vuelos + +// wales : 2014-05-08 Nominet UK +wales + +// walmart : 2015-07-31 Wal-Mart Stores, Inc. +walmart + +// walter : 2014-11-13 Sandvik AB +walter + +// wang : 2013-10-24 Zodiac Wang Limited +wang + +// wanggou : 2014-12-18 Amazon Registry Services, Inc. +wanggou + +// watch : 2013-11-14 Binky Moon, LLC +watch + +// watches : 2014-12-22 Richemont DNS Inc. +watches + +// weather : 2015-01-08 International Business Machines Corporation +weather + +// weatherchannel : 2015-03-12 International Business Machines Corporation +weatherchannel + +// webcam : 2014-01-23 dot Webcam Limited +webcam + +// weber : 2015-06-04 Saint-Gobain Weber SA +weber + +// website : 2014-04-03 DotWebsite Inc. +website + +// wedding : 2014-04-24 Minds + Machines Group Limited +wedding + +// weibo : 2015-03-05 Sina Corporation +weibo + +// weir : 2015-01-29 Weir Group IP Limited +weir + +// whoswho : 2014-02-20 Who's Who Registry +whoswho + +// wien : 2013-10-28 punkt.wien GmbH +wien + +// wiki : 2013-11-07 Top Level Design, LLC +wiki + +// williamhill : 2014-03-13 William Hill Organization Limited +williamhill + +// win : 2014-11-20 First Registry Limited +win + +// windows : 2014-12-18 Microsoft Corporation +windows + +// wine : 2015-06-18 Binky Moon, LLC +wine + +// winners : 2015-07-16 The TJX Companies, Inc. +winners + +// wme : 2014-02-13 William Morris Endeavor Entertainment, LLC +wme + +// wolterskluwer : 2015-08-06 Wolters Kluwer N.V. +wolterskluwer + +// woodside : 2015-07-09 Woodside Petroleum Limited +woodside + +// work : 2013-12-19 Minds + Machines Group Limited +work + +// works : 2013-11-14 Binky Moon, LLC +works + +// world : 2014-06-12 Binky Moon, LLC +world + +// wow : 2015-10-08 Amazon Registry Services, Inc. +wow + +// wtc : 2013-12-19 World Trade Centers Association, Inc. +wtc + +// wtf : 2014-03-06 Binky Moon, LLC +wtf + +// xbox : 2014-12-18 Microsoft Corporation +xbox + +// xerox : 2014-10-24 Xerox DNHC LLC +xerox + +// xfinity : 2015-07-09 Comcast IP Holdings I, LLC +xfinity + +// xihuan : 2015-01-08 Beijing Qihu Keji Co., Ltd. +xihuan + +// xin : 2014-12-11 Elegant Leader Limited +xin + +// xn--11b4c3d : 2015-01-15 VeriSign Sarl +कॉम + +// xn--1ck2e1b : 2015-02-26 Amazon Registry Services, Inc. +セール + +// xn--1qqw23a : 2014-01-09 Guangzhou YU Wei Information Technology Co., Ltd. +佛山 + +// xn--30rr7y : 2014-06-12 Excellent First Limited +慈善 + +// xn--3bst00m : 2013-09-13 Eagle Horizon Limited +集团 + +// xn--3ds443g : 2013-09-08 TLD REGISTRY LIMITED OY +在线 + +// xn--3oq18vl8pn36a : 2015-07-02 Volkswagen (China) Investment Co., Ltd. +大众汽车 + +// xn--3pxu8k : 2015-01-15 VeriSign Sarl +点看 + +// xn--42c2d9a : 2015-01-15 VeriSign Sarl +คอม + +// xn--45q11c : 2013-11-21 Zodiac Gemini Ltd +八卦 + +// xn--4gbrim : 2013-10-04 Fans TLD Limited +موقع + +// xn--55qw42g : 2013-11-08 China Organizational Name Administration Center +公益 + +// xn--55qx5d : 2013-11-14 China Internet Network Information Center (CNNIC) +公司 + +// xn--5su34j936bgsg : 2015-09-03 Shangri‐La International Hotel Management Limited +香格里拉 + +// xn--5tzm5g : 2014-12-22 Global Website TLD Asia Limited +网站 + +// xn--6frz82g : 2013-09-23 Afilias Limited +移动 + +// xn--6qq986b3xl : 2013-09-13 Tycoon Treasure Limited +我爱你 + +// xn--80adxhks : 2013-12-19 Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID) +москва + +// xn--80aqecdr1a : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +католик + +// xn--80asehdb : 2013-07-14 CORE Association +онлайн + +// xn--80aswg : 2013-07-14 CORE Association +сайт + +// xn--8y0a063a : 2015-03-26 China United Network Communications Corporation Limited +联通 + +// xn--9dbq2a : 2015-01-15 VeriSign Sarl +קום + +// xn--9et52u : 2014-06-12 RISE VICTORY LIMITED +时尚 + +// xn--9krt00a : 2015-03-12 Sina Corporation +微博 + +// xn--b4w605ferd : 2014-08-07 Temasek Holdings (Private) Limited +淡马锡 + +// xn--bck1b9a5dre4c : 2015-02-26 Amazon Registry Services, Inc. +ファッション + +// xn--c1avg : 2013-11-14 Public Interest Registry +орг + +// xn--c2br7g : 2015-01-15 VeriSign Sarl +नेट + +// xn--cck2b3b : 2015-02-26 Amazon Registry Services, Inc. +ストア + +// xn--cckwcxetd : 2019-12-19 Amazon Registry Services, Inc. +アマゾン + +// xn--cg4bki : 2013-09-27 SAMSUNG SDS CO., LTD +삼성 + +// xn--czr694b : 2014-01-16 Internet DotTrademark Organisation Limited +商标 + +// xn--czrs0t : 2013-12-19 Binky Moon, LLC +商店 + +// xn--czru2d : 2013-11-21 Zodiac Aquarius Limited +商城 + +// xn--d1acj3b : 2013-11-20 The Foundation for Network Initiatives “The Smart Internet” +дети + +// xn--eckvdtc9d : 2014-12-18 Amazon Registry Services, Inc. +ポイント + +// xn--efvy88h : 2014-08-22 Guangzhou YU Wei Information Technology Co., Ltd. +新闻 + +// xn--fct429k : 2015-04-09 Amazon Registry Services, Inc. +家電 + +// xn--fhbei : 2015-01-15 VeriSign Sarl +كوم + +// xn--fiq228c5hs : 2013-09-08 TLD REGISTRY LIMITED OY +中文网 + +// xn--fiq64b : 2013-10-14 CITIC Group Corporation +中信 + +// xn--fjq720a : 2014-05-22 Binky Moon, LLC +娱乐 + +// xn--flw351e : 2014-07-31 Charleston Road Registry Inc. +谷歌 + +// xn--fzys8d69uvgm : 2015-05-14 PCCW Enterprises Limited +電訊盈科 + +// xn--g2xx48c : 2015-01-30 Nawang Heli(Xiamen) Network Service Co., LTD. +购物 + +// xn--gckr3f0f : 2015-02-26 Amazon Registry Services, Inc. +クラウド + +// xn--gk3at1e : 2015-10-08 Amazon Registry Services, Inc. +通販 + +// xn--hxt814e : 2014-05-15 Zodiac Taurus Limited +网店 + +// xn--i1b6b1a6a2e : 2013-11-14 Public Interest Registry +संगठन + +// xn--imr513n : 2014-12-11 Internet DotTrademark Organisation Limited +餐厅 + +// xn--io0a7i : 2013-11-14 China Internet Network Information Center (CNNIC) +网络 + +// xn--j1aef : 2015-01-15 VeriSign Sarl +ком + +// xn--jlq480n2rg : 2019-12-19 Amazon Registry Services, Inc. +亚马逊 + +// xn--jlq61u9w7b : 2015-01-08 Nokia Corporation +诺基亚 + +// xn--jvr189m : 2015-02-26 Amazon Registry Services, Inc. +食品 + +// xn--kcrx77d1x4a : 2014-11-07 Koninklijke Philips N.V. +飞利浦 + +// xn--kput3i : 2014-02-13 Beijing RITT-Net Technology Development Co., Ltd +手机 + +// xn--mgba3a3ejt : 2014-11-20 Aramco Services Company +ارامكو + +// xn--mgba7c0bbn0a : 2015-05-14 Crescent Holding GmbH +العليان + +// xn--mgbaakc7dvf : 2015-09-03 Emirates Telecommunications Corporation (trading as Etisalat) +اتصالات + +// xn--mgbab2bd : 2013-10-31 CORE Association +بازار + +// xn--mgbca7dzdo : 2015-07-30 Abu Dhabi Systems and Information Centre +ابوظبي + +// xn--mgbi4ecexp : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +كاثوليك + +// xn--mgbt3dhd : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +همراه + +// xn--mk1bu44c : 2015-01-15 VeriSign Sarl +닷컴 + +// xn--mxtq1m : 2014-03-06 Net-Chinese Co., Ltd. +政府 + +// xn--ngbc5azd : 2013-07-13 International Domain Registry Pty. Ltd. +شبكة + +// xn--ngbe9e0a : 2014-12-04 Kuwait Finance House +بيتك + +// xn--ngbrx : 2015-11-12 League of Arab States +عرب + +// xn--nqv7f : 2013-11-14 Public Interest Registry +机构 + +// xn--nqv7fs00ema : 2013-11-14 Public Interest Registry +组织机构 + +// xn--nyqy26a : 2014-11-07 Stable Tone Limited +健康 + +// xn--otu796d : 2017-08-06 Jiang Yu Liang Cai Technology Company Limited +招聘 + +// xn--p1acf : 2013-12-12 Rusnames Limited +рус + +// xn--pssy2u : 2015-01-15 VeriSign Sarl +大拿 + +// xn--q9jyb4c : 2013-09-17 Charleston Road Registry Inc. +みんな + +// xn--qcka1pmc : 2014-07-31 Charleston Road Registry Inc. +グーグル + +// xn--rhqv96g : 2013-09-11 Stable Tone Limited +世界 + +// xn--rovu88b : 2015-02-26 Amazon Registry Services, Inc. +書籍 + +// xn--ses554g : 2014-01-16 KNET Co., Ltd. +网址 + +// xn--t60b56a : 2015-01-15 VeriSign Sarl +닷넷 + +// xn--tckwe : 2015-01-15 VeriSign Sarl +コム + +// xn--tiq49xqyj : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +天主教 + +// xn--unup4y : 2013-07-14 Binky Moon, LLC +游戏 + +// xn--vermgensberater-ctb : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG +vermögensberater + +// xn--vermgensberatung-pwb : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG +vermögensberatung + +// xn--vhquv : 2013-08-27 Binky Moon, LLC +企业 + +// xn--vuq861b : 2014-10-16 Beijing Tele-info Network Technology Co., Ltd. +信息 + +// xn--w4r85el8fhu5dnra : 2015-04-30 Kerry Trading Co. Limited +嘉里大酒店 + +// xn--w4rs40l : 2015-07-30 Kerry Trading Co. Limited +嘉里 + +// xn--xhq521b : 2013-11-14 Guangzhou YU Wei Information Technology Co., Ltd. +广东 + +// xn--zfr164b : 2013-11-08 China Organizational Name Administration Center +政务 + +// xyz : 2013-12-05 XYZ.COM LLC +xyz + +// yachts : 2014-01-09 XYZ.COM LLC +yachts + +// yahoo : 2015-04-02 Yahoo! Domain Services Inc. +yahoo + +// yamaxun : 2014-12-18 Amazon Registry Services, Inc. +yamaxun + +// yandex : 2014-04-10 Yandex Europe B.V. +yandex + +// yodobashi : 2014-11-20 YODOBASHI CAMERA CO.,LTD. +yodobashi + +// yoga : 2014-05-29 Minds + Machines Group Limited +yoga + +// yokohama : 2013-12-12 GMO Registry, Inc. +yokohama + +// you : 2015-04-09 Amazon Registry Services, Inc. +you + +// youtube : 2014-05-01 Charleston Road Registry Inc. +youtube + +// yun : 2015-01-08 Beijing Qihu Keji Co., Ltd. +yun + +// zappos : 2015-06-25 Amazon Registry Services, Inc. +zappos + +// zara : 2014-11-07 Industria de Diseño Textil, S.A. (INDITEX, S.A.) +zara + +// zero : 2014-12-18 Amazon Registry Services, Inc. +zero + +// zip : 2014-05-08 Charleston Road Registry Inc. +zip + +// zone : 2013-11-14 Binky Moon, LLC +zone + +// zuerich : 2014-11-07 Kanton Zürich (Canton of Zurich) +zuerich + + +// ===END ICANN DOMAINS=== +// ===BEGIN PRIVATE DOMAINS=== +// (Note: these are in alphabetical order by company name) + +// 1GB LLC : https://www.1gb.ua/ +// Submitted by 1GB LLC +cc.ua +inf.ua +ltd.ua + +// 611coin : https://611project.org/ +611.to + +// Adobe : https://www.adobe.com/ +// Submitted by Ian Boston +adobeaemcloud.com +adobeaemcloud.net +*.dev.adobeaemcloud.com + +// Agnat sp. z o.o. : https://domena.pl +// Submitted by Przemyslaw Plewa +beep.pl + +// alboto.ca : http://alboto.ca +// Submitted by Anton Avramov +barsy.ca + +// Alces Software Ltd : http://alces-software.com +// Submitted by Mark J. Titorenko +*.compute.estate +*.alces.network + +// all-inkl.com : https://all-inkl.com +// Submitted by Werner Kaltofen +kasserver.com + +// Altervista: https://www.altervista.org +// Submitted by Carlo Cannas +altervista.org + +// alwaysdata : https://www.alwaysdata.com +// Submitted by Cyril +alwaysdata.net + +// Amazon CloudFront : https://aws.amazon.com/cloudfront/ +// Submitted by Donavan Miller +cloudfront.net + +// Amazon Elastic Compute Cloud : https://aws.amazon.com/ec2/ +// Submitted by Luke Wells +*.compute.amazonaws.com +*.compute-1.amazonaws.com +*.compute.amazonaws.com.cn +us-east-1.amazonaws.com + +// Amazon Elastic Beanstalk : https://aws.amazon.com/elasticbeanstalk/ +// Submitted by Luke Wells +cn-north-1.eb.amazonaws.com.cn +cn-northwest-1.eb.amazonaws.com.cn +elasticbeanstalk.com +ap-northeast-1.elasticbeanstalk.com +ap-northeast-2.elasticbeanstalk.com +ap-northeast-3.elasticbeanstalk.com +ap-south-1.elasticbeanstalk.com +ap-southeast-1.elasticbeanstalk.com +ap-southeast-2.elasticbeanstalk.com +ca-central-1.elasticbeanstalk.com +eu-central-1.elasticbeanstalk.com +eu-west-1.elasticbeanstalk.com +eu-west-2.elasticbeanstalk.com +eu-west-3.elasticbeanstalk.com +sa-east-1.elasticbeanstalk.com +us-east-1.elasticbeanstalk.com +us-east-2.elasticbeanstalk.com +us-gov-west-1.elasticbeanstalk.com +us-west-1.elasticbeanstalk.com +us-west-2.elasticbeanstalk.com + +// Amazon Elastic Load Balancing : https://aws.amazon.com/elasticloadbalancing/ +// Submitted by Luke Wells +*.elb.amazonaws.com +*.elb.amazonaws.com.cn + +// Amazon S3 : https://aws.amazon.com/s3/ +// Submitted by Luke Wells +s3.amazonaws.com +s3-ap-northeast-1.amazonaws.com +s3-ap-northeast-2.amazonaws.com +s3-ap-south-1.amazonaws.com +s3-ap-southeast-1.amazonaws.com +s3-ap-southeast-2.amazonaws.com +s3-ca-central-1.amazonaws.com +s3-eu-central-1.amazonaws.com +s3-eu-west-1.amazonaws.com +s3-eu-west-2.amazonaws.com +s3-eu-west-3.amazonaws.com +s3-external-1.amazonaws.com +s3-fips-us-gov-west-1.amazonaws.com +s3-sa-east-1.amazonaws.com +s3-us-gov-west-1.amazonaws.com +s3-us-east-2.amazonaws.com +s3-us-west-1.amazonaws.com +s3-us-west-2.amazonaws.com +s3.ap-northeast-2.amazonaws.com +s3.ap-south-1.amazonaws.com +s3.cn-north-1.amazonaws.com.cn +s3.ca-central-1.amazonaws.com +s3.eu-central-1.amazonaws.com +s3.eu-west-2.amazonaws.com +s3.eu-west-3.amazonaws.com +s3.us-east-2.amazonaws.com +s3.dualstack.ap-northeast-1.amazonaws.com +s3.dualstack.ap-northeast-2.amazonaws.com +s3.dualstack.ap-south-1.amazonaws.com +s3.dualstack.ap-southeast-1.amazonaws.com +s3.dualstack.ap-southeast-2.amazonaws.com +s3.dualstack.ca-central-1.amazonaws.com +s3.dualstack.eu-central-1.amazonaws.com +s3.dualstack.eu-west-1.amazonaws.com +s3.dualstack.eu-west-2.amazonaws.com +s3.dualstack.eu-west-3.amazonaws.com +s3.dualstack.sa-east-1.amazonaws.com +s3.dualstack.us-east-1.amazonaws.com +s3.dualstack.us-east-2.amazonaws.com +s3-website-us-east-1.amazonaws.com +s3-website-us-west-1.amazonaws.com +s3-website-us-west-2.amazonaws.com +s3-website-ap-northeast-1.amazonaws.com +s3-website-ap-southeast-1.amazonaws.com +s3-website-ap-southeast-2.amazonaws.com +s3-website-eu-west-1.amazonaws.com +s3-website-sa-east-1.amazonaws.com +s3-website.ap-northeast-2.amazonaws.com +s3-website.ap-south-1.amazonaws.com +s3-website.ca-central-1.amazonaws.com +s3-website.eu-central-1.amazonaws.com +s3-website.eu-west-2.amazonaws.com +s3-website.eu-west-3.amazonaws.com +s3-website.us-east-2.amazonaws.com + +// Amsterdam Wireless: https://www.amsterdamwireless.nl/ +// Submitted by Imre Jonk +amsw.nl + +// Amune : https://amune.org/ +// Submitted by Team Amune +t3l3p0rt.net +tele.amune.org + +// Apigee : https://apigee.com/ +// Submitted by Apigee Security Team +apigee.io + +// Aptible : https://www.aptible.com/ +// Submitted by Thomas Orozco +on-aptible.com + +// ASEINet : https://www.aseinet.com/ +// Submitted by Asei SEKIGUCHI +user.aseinet.ne.jp +gv.vc +d.gv.vc + +// Asociación Amigos de la Informática "Euskalamiga" : http://encounter.eus/ +// Submitted by Hector Martin +user.party.eus + +// Association potager.org : https://potager.org/ +// Submitted by Lunar +pimienta.org +poivron.org +potager.org +sweetpepper.org + +// ASUSTOR Inc. : http://www.asustor.com +// Submitted by Vincent Tseng +myasustor.com + +// AVM : https://avm.de +// Submitted by Andreas Weise +myfritz.net + +// AW AdvisorWebsites.com Software Inc : https://advisorwebsites.com +// Submitted by James Kennedy +*.awdev.ca +*.advisor.ws + +// b-data GmbH : https://www.b-data.io +// Submitted by Olivier Benz +b-data.io + +// backplane : https://www.backplane.io +// Submitted by Anthony Voutas +backplaneapp.io + +// Balena : https://www.balena.io +// Submitted by Petros Angelatos +balena-devices.com + +// Banzai Cloud +// Submitted by Janos Matyas +*.banzai.cloud +app.banzaicloud.io +*.backyards.banzaicloud.io + + +// BetaInABox +// Submitted by Adrian +betainabox.com + +// BinaryLane : http://www.binarylane.com +// Submitted by Nathan O'Sullivan +bnr.la + +// Blackbaud, Inc. : https://www.blackbaud.com +// Submitted by Paul Crowder +blackbaudcdn.net + +// Blatech : http://www.blatech.net +// Submitted by Luke Bratch +of.je + +// Boomla : https://boomla.com +// Submitted by Tibor Halter +boomla.net + +// Boxfuse : https://boxfuse.com +// Submitted by Axel Fontaine +boxfuse.io + +// bplaced : https://www.bplaced.net/ +// Submitted by Miroslav Bozic +square7.ch +bplaced.com +bplaced.de +square7.de +bplaced.net +square7.net + +// BrowserSafetyMark +// Submitted by Dave Tharp +browsersafetymark.io + +// Bytemark Hosting : https://www.bytemark.co.uk +// Submitted by Paul Cammish +uk0.bigv.io +dh.bytemark.co.uk +vm.bytemark.co.uk + +// callidomus : https://www.callidomus.com/ +// Submitted by Marcus Popp +mycd.eu + +// Carrd : https://carrd.co +// Submitted by AJ +carrd.co +crd.co +uwu.ai + +// CentralNic : http://www.centralnic.com/names/domains +// Submitted by registry +ae.org +br.com +cn.com +com.de +com.se +de.com +eu.com +gb.net +hu.net +jp.net +jpn.com +mex.com +ru.com +sa.com +se.net +uk.com +uk.net +us.com +za.bz +za.com + +// No longer operated by CentralNic, these entries should be adopted and/or removed by current operators +// Submitted by Gavin Brown +ar.com +gb.com +hu.com +kr.com +no.com +qc.com +uy.com + +// Africa.com Web Solutions Ltd : https://registry.africa.com +// Submitted by Gavin Brown +africa.com + +// iDOT Services Limited : http://www.domain.gr.com +// Submitted by Gavin Brown +gr.com + +// Radix FZC : http://domains.in.net +// Submitted by Gavin Brown +in.net +web.in + +// US REGISTRY LLC : http://us.org +// Submitted by Gavin Brown +us.org + +// co.com Registry, LLC : https://registry.co.com +// Submitted by Gavin Brown +co.com + +// Roar Domains LLC : https://roar.basketball/ +// Submitted by Gavin Brown +aus.basketball +nz.basketball + +// BRS Media : https://brsmedia.com/ +// Submitted by Gavin Brown +radio.am +radio.fm + +// Globe Hosting SRL : https://www.globehosting.com/ +// Submitted by Gavin Brown +co.ro +shop.ro + +// c.la : http://www.c.la/ +c.la + +// certmgr.org : https://certmgr.org +// Submitted by B. Blechschmidt +certmgr.org + +// Civilized Discourse Construction Kit, Inc. : https://www.discourse.org/ +// Submitted by Rishabh Nambiar & Michael Brown +discourse.group +discourse.team + +// ClearVox : http://www.clearvox.nl/ +// Submitted by Leon Rowland +virtueeldomein.nl + +// Clever Cloud : https://www.clever-cloud.com/ +// Submitted by Quentin Adam +cleverapps.io + +// Clerk : https://www.clerk.dev +// Submitted by Colin Sidoti +*.lcl.dev +*.stg.dev + +// Clic2000 : https://clic2000.fr +// Submitted by Mathilde Blanchemanche +clic2000.net + +// Cloud66 : https://www.cloud66.com/ +// Submitted by Khash Sajadi +c66.me +cloud66.ws +cloud66.zone + +// CloudAccess.net : https://www.cloudaccess.net/ +// Submitted by Pawel Panek +jdevcloud.com +wpdevcloud.com +cloudaccess.host +freesite.host +cloudaccess.net + +// cloudControl : https://www.cloudcontrol.com/ +// Submitted by Tobias Wilken +cloudcontrolled.com +cloudcontrolapp.com + +// Cloudera, Inc. : https://www.cloudera.com/ +// Submitted by Philip Langdale +cloudera.site + +// Cloudflare, Inc. : https://www.cloudflare.com/ +// Submitted by Cloudflare Team +pages.dev +trycloudflare.com +workers.dev + +// Clovyr : https://clovyr.io +// Submitted by Patrick Nielsen +wnext.app + +// co.ca : http://registry.co.ca/ +co.ca + +// Co & Co : https://co-co.nl/ +// Submitted by Govert Versluis +*.otap.co + +// i-registry s.r.o. : http://www.i-registry.cz/ +// Submitted by Martin Semrad +co.cz + +// CDN77.com : http://www.cdn77.com +// Submitted by Jan Krpes +c.cdn77.org +cdn77-ssl.net +r.cdn77.net +rsc.cdn77.org +ssl.origin.cdn77-secure.org + +// Cloud DNS Ltd : http://www.cloudns.net +// Submitted by Aleksander Hristov +cloudns.asia +cloudns.biz +cloudns.club +cloudns.cc +cloudns.eu +cloudns.in +cloudns.info +cloudns.org +cloudns.pro +cloudns.pw +cloudns.us + +// CNPY : https://cnpy.gdn +// Submitted by Angelo Gladding +cnpy.gdn + +// CoDNS B.V. +co.nl +co.no + +// Combell.com : https://www.combell.com +// Submitted by Thomas Wouters +webhosting.be +hosting-cluster.nl + +// Coordination Center for TLD RU and XN--P1AI : https://cctld.ru/en/domains/domens_ru/reserved/ +// Submitted by George Georgievsky +ac.ru +edu.ru +gov.ru +int.ru +mil.ru +test.ru + +// COSIMO GmbH : http://www.cosimo.de +// Submitted by Rene Marticke +dyn.cosidns.de +dynamisches-dns.de +dnsupdater.de +internet-dns.de +l-o-g-i-n.de +dynamic-dns.info +feste-ip.net +knx-server.net +static-access.net + +// Craynic, s.r.o. : http://www.craynic.com/ +// Submitted by Ales Krajnik +realm.cz + +// Cryptonomic : https://cryptonomic.net/ +// Submitted by Andrew Cady +*.cryptonomic.net + +// Cupcake : https://cupcake.io/ +// Submitted by Jonathan Rudenberg +cupcake.is + +// Curv UG : https://curv-labs.de/ +// Submitted by Marvin Wiesner +curv.dev + +// Customer OCI - Oracle Dyn https://cloud.oracle.com/home https://dyn.com/dns/ +// Submitted by Gregory Drake +// Note: This is intended to also include customer-oci.com due to wildcards implicitly including the current label +*.customer-oci.com +*.oci.customer-oci.com +*.ocp.customer-oci.com +*.ocs.customer-oci.com + +// cyon GmbH : https://www.cyon.ch/ +// Submitted by Dominic Luechinger +cyon.link +cyon.site + +// Danger Science Group: https://dangerscience.com/ +// Submitted by Skylar MacDonald +fnwk.site +folionetwork.site +platform0.app + +// Daplie, Inc : https://daplie.com +// Submitted by AJ ONeal +daplie.me +localhost.daplie.me + +// Datto, Inc. : https://www.datto.com/ +// Submitted by Philipp Heckel +dattolocal.com +dattorelay.com +dattoweb.com +mydatto.com +dattolocal.net +mydatto.net + +// Dansk.net : http://www.dansk.net/ +// Submitted by Anani Voule +biz.dk +co.dk +firm.dk +reg.dk +store.dk + +// dappnode.io : https://dappnode.io/ +// Submitted by Abel Boldu / DAppNode Team +dyndns.dappnode.io + +// dapps.earth : https://dapps.earth/ +// Submitted by Daniil Burdakov +*.dapps.earth +*.bzz.dapps.earth + +// Dark, Inc. : https://darklang.com +// Submitted by Paul Biggar +builtwithdark.com + +// Datawire, Inc : https://www.datawire.io +// Submitted by Richard Li +edgestack.me + +// Debian : https://www.debian.org/ +// Submitted by Peter Palfrader / Debian Sysadmin Team +debian.net + +// deSEC : https://desec.io/ +// Submitted by Peter Thomassen +dedyn.io + +// DNS Africa Ltd https://dns.business +// Submitted by Calvin Browne +jozi.biz + +// DNShome : https://www.dnshome.de/ +// Submitted by Norbert Auler +dnshome.de + +// DotArai : https://www.dotarai.com/ +// Submitted by Atsadawat Netcharadsang +online.th +shop.th + +// DrayTek Corp. : https://www.draytek.com/ +// Submitted by Paul Fang +drayddns.com + +// DreamHost : http://www.dreamhost.com/ +// Submitted by Andrew Farmer +dreamhosters.com + +// Drobo : http://www.drobo.com/ +// Submitted by Ricardo Padilha +mydrobo.com + +// Drud Holdings, LLC. : https://www.drud.com/ +// Submitted by Kevin Bridges +drud.io +drud.us + +// DuckDNS : http://www.duckdns.org/ +// Submitted by Richard Harper +duckdns.org + +// Bip : https://bip.sh +// Submitted by Joel Kennedy +bip.sh + +// bitbridge.net : Submitted by Craig Welch, abeliidev@gmail.com +bitbridge.net + +// dy.fi : http://dy.fi/ +// Submitted by Heikki Hannikainen +dy.fi +tunk.org + +// DynDNS.com : http://www.dyndns.com/services/dns/dyndns/ +dyndns-at-home.com +dyndns-at-work.com +dyndns-blog.com +dyndns-free.com +dyndns-home.com +dyndns-ip.com +dyndns-mail.com +dyndns-office.com +dyndns-pics.com +dyndns-remote.com +dyndns-server.com +dyndns-web.com +dyndns-wiki.com +dyndns-work.com +dyndns.biz +dyndns.info +dyndns.org +dyndns.tv +at-band-camp.net +ath.cx +barrel-of-knowledge.info +barrell-of-knowledge.info +better-than.tv +blogdns.com +blogdns.net +blogdns.org +blogsite.org +boldlygoingnowhere.org +broke-it.net +buyshouses.net +cechire.com +dnsalias.com +dnsalias.net +dnsalias.org +dnsdojo.com +dnsdojo.net +dnsdojo.org +does-it.net +doesntexist.com +doesntexist.org +dontexist.com +dontexist.net +dontexist.org +doomdns.com +doomdns.org +dvrdns.org +dyn-o-saur.com +dynalias.com +dynalias.net +dynalias.org +dynathome.net +dyndns.ws +endofinternet.net +endofinternet.org +endoftheinternet.org +est-a-la-maison.com +est-a-la-masion.com +est-le-patron.com +est-mon-blogueur.com +for-better.biz +for-more.biz +for-our.info +for-some.biz +for-the.biz +forgot.her.name +forgot.his.name +from-ak.com +from-al.com +from-ar.com +from-az.net +from-ca.com +from-co.net +from-ct.com +from-dc.com +from-de.com +from-fl.com +from-ga.com +from-hi.com +from-ia.com +from-id.com +from-il.com +from-in.com +from-ks.com +from-ky.com +from-la.net +from-ma.com +from-md.com +from-me.org +from-mi.com +from-mn.com +from-mo.com +from-ms.com +from-mt.com +from-nc.com +from-nd.com +from-ne.com +from-nh.com +from-nj.com +from-nm.com +from-nv.com +from-ny.net +from-oh.com +from-ok.com +from-or.com +from-pa.com +from-pr.com +from-ri.com +from-sc.com +from-sd.com +from-tn.com +from-tx.com +from-ut.com +from-va.com +from-vt.com +from-wa.com +from-wi.com +from-wv.com +from-wy.com +ftpaccess.cc +fuettertdasnetz.de +game-host.org +game-server.cc +getmyip.com +gets-it.net +go.dyndns.org +gotdns.com +gotdns.org +groks-the.info +groks-this.info +ham-radio-op.net +here-for-more.info +hobby-site.com +hobby-site.org +home.dyndns.org +homedns.org +homeftp.net +homeftp.org +homeip.net +homelinux.com +homelinux.net +homelinux.org +homeunix.com +homeunix.net +homeunix.org +iamallama.com +in-the-band.net +is-a-anarchist.com +is-a-blogger.com +is-a-bookkeeper.com +is-a-bruinsfan.org +is-a-bulls-fan.com +is-a-candidate.org +is-a-caterer.com +is-a-celticsfan.org +is-a-chef.com +is-a-chef.net +is-a-chef.org +is-a-conservative.com +is-a-cpa.com +is-a-cubicle-slave.com +is-a-democrat.com +is-a-designer.com +is-a-doctor.com +is-a-financialadvisor.com +is-a-geek.com +is-a-geek.net +is-a-geek.org +is-a-green.com +is-a-guru.com +is-a-hard-worker.com +is-a-hunter.com +is-a-knight.org +is-a-landscaper.com +is-a-lawyer.com +is-a-liberal.com +is-a-libertarian.com +is-a-linux-user.org +is-a-llama.com +is-a-musician.com +is-a-nascarfan.com +is-a-nurse.com +is-a-painter.com +is-a-patsfan.org +is-a-personaltrainer.com +is-a-photographer.com +is-a-player.com +is-a-republican.com +is-a-rockstar.com +is-a-socialist.com +is-a-soxfan.org +is-a-student.com +is-a-teacher.com +is-a-techie.com +is-a-therapist.com +is-an-accountant.com +is-an-actor.com +is-an-actress.com +is-an-anarchist.com +is-an-artist.com +is-an-engineer.com +is-an-entertainer.com +is-by.us +is-certified.com +is-found.org +is-gone.com +is-into-anime.com +is-into-cars.com +is-into-cartoons.com +is-into-games.com +is-leet.com +is-lost.org +is-not-certified.com +is-saved.org +is-slick.com +is-uberleet.com +is-very-bad.org +is-very-evil.org +is-very-good.org +is-very-nice.org +is-very-sweet.org +is-with-theband.com +isa-geek.com +isa-geek.net +isa-geek.org +isa-hockeynut.com +issmarterthanyou.com +isteingeek.de +istmein.de +kicks-ass.net +kicks-ass.org +knowsitall.info +land-4-sale.us +lebtimnetz.de +leitungsen.de +likes-pie.com +likescandy.com +merseine.nu +mine.nu +misconfused.org +mypets.ws +myphotos.cc +neat-url.com +office-on-the.net +on-the-web.tv +podzone.net +podzone.org +readmyblog.org +saves-the-whales.com +scrapper-site.net +scrapping.cc +selfip.biz +selfip.com +selfip.info +selfip.net +selfip.org +sells-for-less.com +sells-for-u.com +sells-it.net +sellsyourhome.org +servebbs.com +servebbs.net +servebbs.org +serveftp.net +serveftp.org +servegame.org +shacknet.nu +simple-url.com +space-to-rent.com +stuff-4-sale.org +stuff-4-sale.us +teaches-yoga.com +thruhere.net +traeumtgerade.de +webhop.biz +webhop.info +webhop.net +webhop.org +worse-than.tv +writesthisblog.com + +// ddnss.de : https://www.ddnss.de/ +// Submitted by Robert Niedziela +ddnss.de +dyn.ddnss.de +dyndns.ddnss.de +dyndns1.de +dyn-ip24.de +home-webserver.de +dyn.home-webserver.de +myhome-server.de +ddnss.org + +// Definima : http://www.definima.com/ +// Submitted by Maxence Bitterli +definima.net +definima.io + +// DigitalOcean : https://digitalocean.com/ +// Submitted by Braxton Huggins +ondigitalocean.app + +// dnstrace.pro : https://dnstrace.pro/ +// Submitted by Chris Partridge +bci.dnstrace.pro + +// Dynu.com : https://www.dynu.com/ +// Submitted by Sue Ye +ddnsfree.com +ddnsgeek.com +giize.com +gleeze.com +kozow.com +loseyourip.com +ooguy.com +theworkpc.com +casacam.net +dynu.net +accesscam.org +camdvr.org +freeddns.org +mywire.org +webredirect.org +myddns.rocks +blogsite.xyz + +// dynv6 : https://dynv6.com +// Submitted by Dominik Menke +dynv6.net + +// E4YOU spol. s.r.o. : https://e4you.cz/ +// Submitted by Vladimir Dudr +e4.cz + +// En root‽ : https://en-root.org +// Submitted by Emmanuel Raviart +en-root.fr + +// Enalean SAS: https://www.enalean.com +// Submitted by Thomas Cottier +mytuleap.com + +// ECG Robotics, Inc: https://ecgrobotics.org +// Submitted by +onred.one +staging.onred.one + +// One.com: https://www.one.com/ +// Submitted by Jacob Bunk Nielsen +service.one + +// Enonic : http://enonic.com/ +// Submitted by Erik Kaareng-Sunde +enonic.io +customer.enonic.io + +// EU.org https://eu.org/ +// Submitted by Pierre Beyssac +eu.org +al.eu.org +asso.eu.org +at.eu.org +au.eu.org +be.eu.org +bg.eu.org +ca.eu.org +cd.eu.org +ch.eu.org +cn.eu.org +cy.eu.org +cz.eu.org +de.eu.org +dk.eu.org +edu.eu.org +ee.eu.org +es.eu.org +fi.eu.org +fr.eu.org +gr.eu.org +hr.eu.org +hu.eu.org +ie.eu.org +il.eu.org +in.eu.org +int.eu.org +is.eu.org +it.eu.org +jp.eu.org +kr.eu.org +lt.eu.org +lu.eu.org +lv.eu.org +mc.eu.org +me.eu.org +mk.eu.org +mt.eu.org +my.eu.org +net.eu.org +ng.eu.org +nl.eu.org +no.eu.org +nz.eu.org +paris.eu.org +pl.eu.org +pt.eu.org +q-a.eu.org +ro.eu.org +ru.eu.org +se.eu.org +si.eu.org +sk.eu.org +tr.eu.org +uk.eu.org +us.eu.org + +// Evennode : http://www.evennode.com/ +// Submitted by Michal Kralik +eu-1.evennode.com +eu-2.evennode.com +eu-3.evennode.com +eu-4.evennode.com +us-1.evennode.com +us-2.evennode.com +us-3.evennode.com +us-4.evennode.com + +// eDirect Corp. : https://hosting.url.com.tw/ +// Submitted by C.S. chang +twmail.cc +twmail.net +twmail.org +mymailer.com.tw +url.tw + +// Fabrica Technologies, Inc. : https://www.fabrica.dev/ +// Submitted by Eric Jiang +onfabrica.com + +// Facebook, Inc. +// Submitted by Peter Ruibal +apps.fbsbx.com + +// FAITID : https://faitid.org/ +// Submitted by Maxim Alzoba +// https://www.flexireg.net/stat_info +ru.net +adygeya.ru +bashkiria.ru +bir.ru +cbg.ru +com.ru +dagestan.ru +grozny.ru +kalmykia.ru +kustanai.ru +marine.ru +mordovia.ru +msk.ru +mytis.ru +nalchik.ru +nov.ru +pyatigorsk.ru +spb.ru +vladikavkaz.ru +vladimir.ru +abkhazia.su +adygeya.su +aktyubinsk.su +arkhangelsk.su +armenia.su +ashgabad.su +azerbaijan.su +balashov.su +bashkiria.su +bryansk.su +bukhara.su +chimkent.su +dagestan.su +east-kazakhstan.su +exnet.su +georgia.su +grozny.su +ivanovo.su +jambyl.su +kalmykia.su +kaluga.su +karacol.su +karaganda.su +karelia.su +khakassia.su +krasnodar.su +kurgan.su +kustanai.su +lenug.su +mangyshlak.su +mordovia.su +msk.su +murmansk.su +nalchik.su +navoi.su +north-kazakhstan.su +nov.su +obninsk.su +penza.su +pokrovsk.su +sochi.su +spb.su +tashkent.su +termez.su +togliatti.su +troitsk.su +tselinograd.su +tula.su +tuva.su +vladikavkaz.su +vladimir.su +vologda.su + +// Fancy Bits, LLC : http://getchannels.com +// Submitted by Aman Gupta +channelsdvr.net +u.channelsdvr.net + +// Fastly Inc. : http://www.fastly.com/ +// Submitted by Fastly Security +fastly-terrarium.com +fastlylb.net +map.fastlylb.net +freetls.fastly.net +map.fastly.net +a.prod.fastly.net +global.prod.fastly.net +a.ssl.fastly.net +b.ssl.fastly.net +global.ssl.fastly.net + +// FASTVPS EESTI OU : https://fastvps.ru/ +// Submitted by Likhachev Vasiliy +fastvps-server.com +fastvps.host +myfast.host +fastvps.site +myfast.space + +// Featherhead : https://featherhead.xyz/ +// Submitted by Simon Menke +fhapp.xyz + +// Fedora : https://fedoraproject.org/ +// submitted by Patrick Uiterwijk +fedorainfracloud.org +fedorapeople.org +cloud.fedoraproject.org +app.os.fedoraproject.org +app.os.stg.fedoraproject.org + +// FearWorks Media Ltd. : https://fearworksmedia.co.uk +// submitted by Keith Fairley +conn.uk +copro.uk +couk.me +ukco.me + +// Fermax : https://fermax.com/ +// submitted by Koen Van Isterdael +mydobiss.com + +// FH Muenster : https://www.fh-muenster.de +// Submitted by Robin Naundorf +fh-muenster.io + +// Filegear Inc. : https://www.filegear.com +// Submitted by Jason Zhu +filegear.me +filegear-au.me +filegear-de.me +filegear-gb.me +filegear-ie.me +filegear-jp.me +filegear-sg.me + +// Firebase, Inc. +// Submitted by Chris Raynor +firebaseapp.com + +// fly.io: https://fly.io +// Submitted by Kurt Mackey +fly.dev +edgeapp.net +shw.io + +// Flynn : https://flynn.io +// Submitted by Jonathan Rudenberg +flynnhosting.net + +// Frederik Braun https://frederik-braun.com +// Submitted by Frederik Braun +0e.vc + +// Freebox : http://www.freebox.fr +// Submitted by Romain Fliedel +freebox-os.com +freeboxos.com +fbx-os.fr +fbxos.fr +freebox-os.fr +freeboxos.fr + +// freedesktop.org : https://www.freedesktop.org +// Submitted by Daniel Stone +freedesktop.org + +// FunkFeuer - Verein zur Förderung freier Netze : https://www.funkfeuer.at +// Submitted by Daniel A. Maierhofer +wien.funkfeuer.at + +// Futureweb OG : http://www.futureweb.at +// Submitted by Andreas Schnederle-Wagner +*.futurecms.at +*.ex.futurecms.at +*.in.futurecms.at +futurehosting.at +futuremailing.at +*.ex.ortsinfo.at +*.kunden.ortsinfo.at +*.statics.cloud + +// GDS : https://www.gov.uk/service-manual/operations/operating-servicegovuk-subdomains +// Submitted by David Illsley +service.gov.uk + +// Gehirn Inc. : https://www.gehirn.co.jp/ +// Submitted by Kohei YOSHIDA +gehirn.ne.jp +usercontent.jp + +// Gentlent, Inc. : https://www.gentlent.com +// Submitted by Tom Klein +gentapps.com +gentlentapis.com +lab.ms +cdn-edges.net + +// GitHub, Inc. +// Submitted by Patrick Toomey +github.io +githubusercontent.com + +// GitLab, Inc. +// Submitted by Alex Hanselka +gitlab.io + +// Gitplac.si - https://gitplac.si +// Submitted by Aljaž Starc +gitapp.si +gitpage.si + +// Glitch, Inc : https://glitch.com +// Submitted by Mads Hartmann +glitch.me + +// GMO Pepabo, Inc. : https://pepabo.com/ +// Submitted by dojineko +lolipop.io + +// GOV.UK Platform as a Service : https://www.cloud.service.gov.uk/ +// Submitted by Tom Whitwell +cloudapps.digital +london.cloudapps.digital + +// GOV.UK Pay : https://www.payments.service.gov.uk/ +// Submitted by Richard Baker +pymnt.uk + +// UKHomeOffice : https://www.gov.uk/government/organisations/home-office +// Submitted by Jon Shanks +homeoffice.gov.uk + +// GlobeHosting, Inc. +// Submitted by Zoltan Egresi +ro.im + +// GoIP DNS Services : http://www.goip.de +// Submitted by Christian Poulter +goip.de + +// Google, Inc. +// Submitted by Eduardo Vela +run.app +a.run.app +web.app +*.0emm.com +appspot.com +*.r.appspot.com +codespot.com +googleapis.com +googlecode.com +pagespeedmobilizer.com +publishproxy.com +withgoogle.com +withyoutube.com +*.gateway.dev +cloud.goog +translate.goog +cloudfunctions.net + +blogspot.ae +blogspot.al +blogspot.am +blogspot.ba +blogspot.be +blogspot.bg +blogspot.bj +blogspot.ca +blogspot.cf +blogspot.ch +blogspot.cl +blogspot.co.at +blogspot.co.id +blogspot.co.il +blogspot.co.ke +blogspot.co.nz +blogspot.co.uk +blogspot.co.za +blogspot.com +blogspot.com.ar +blogspot.com.au +blogspot.com.br +blogspot.com.by +blogspot.com.co +blogspot.com.cy +blogspot.com.ee +blogspot.com.eg +blogspot.com.es +blogspot.com.mt +blogspot.com.ng +blogspot.com.tr +blogspot.com.uy +blogspot.cv +blogspot.cz +blogspot.de +blogspot.dk +blogspot.fi +blogspot.fr +blogspot.gr +blogspot.hk +blogspot.hr +blogspot.hu +blogspot.ie +blogspot.in +blogspot.is +blogspot.it +blogspot.jp +blogspot.kr +blogspot.li +blogspot.lt +blogspot.lu +blogspot.md +blogspot.mk +blogspot.mr +blogspot.mx +blogspot.my +blogspot.nl +blogspot.no +blogspot.pe +blogspot.pt +blogspot.qa +blogspot.re +blogspot.ro +blogspot.rs +blogspot.ru +blogspot.se +blogspot.sg +blogspot.si +blogspot.sk +blogspot.sn +blogspot.td +blogspot.tw +blogspot.ug +blogspot.vn + +// Aaron Marais' Gitlab pages: https://lab.aaronleem.co.za +// Submitted by Aaron Marais +graphox.us + +// Group 53, LLC : https://www.group53.com +// Submitted by Tyler Todd +awsmppl.com + +// Hakaran group: http://hakaran.cz +// Submited by Arseniy Sokolov +fin.ci +free.hr +caa.li +ua.rs +conf.se + +// Handshake : https://handshake.org +// Submitted by Mike Damm +hs.zone +hs.run + +// Hashbang : https://hashbang.sh +hashbang.sh + +// Hasura : https://hasura.io +// Submitted by Shahidh K Muhammed +hasura.app +hasura-app.io + +// Hepforge : https://www.hepforge.org +// Submitted by David Grellscheid +hepforge.org + +// Heroku : https://www.heroku.com/ +// Submitted by Tom Maher +herokuapp.com +herokussl.com + +// Hibernating Rhinos +// Submitted by Oren Eini +myravendb.com +ravendb.community +ravendb.me +development.run +ravendb.run + +// Hong Kong Productivity Council: https://www.hkpc.org/ +// Submitted by SECaaS Team +secaas.hk + +// HOSTBIP REGISTRY : https://www.hostbip.com/ +// Submitted by Atanunu Igbunuroghene +bpl.biz +orx.biz +ng.city +biz.gl +ng.ink +col.ng +firm.ng +gen.ng +ltd.ng +ngo.ng +ng.school +sch.so + +// HostyHosting (hostyhosting.com) +hostyhosting.io + +// Häkkinen.fi +// Submitted by Eero Häkkinen +häkkinen.fi + +// Ici la Lune : http://www.icilalune.com/ +// Submitted by Simon Morvan +*.moonscale.io +moonscale.net + +// iki.fi +// Submitted by Hannu Aronsson +iki.fi + +// Individual Network Berlin e.V. : https://www.in-berlin.de/ +// Submitted by Christian Seitz +dyn-berlin.de +in-berlin.de +in-brb.de +in-butter.de +in-dsl.de +in-dsl.net +in-dsl.org +in-vpn.de +in-vpn.net +in-vpn.org + +// info.at : http://www.info.at/ +biz.at +info.at + +// info.cx : http://info.cx +// Submitted by Jacob Slater +info.cx + +// Interlegis : http://www.interlegis.leg.br +// Submitted by Gabriel Ferreira +ac.leg.br +al.leg.br +am.leg.br +ap.leg.br +ba.leg.br +ce.leg.br +df.leg.br +es.leg.br +go.leg.br +ma.leg.br +mg.leg.br +ms.leg.br +mt.leg.br +pa.leg.br +pb.leg.br +pe.leg.br +pi.leg.br +pr.leg.br +rj.leg.br +rn.leg.br +ro.leg.br +rr.leg.br +rs.leg.br +sc.leg.br +se.leg.br +sp.leg.br +to.leg.br + +// intermetrics GmbH : https://pixolino.com/ +// Submitted by Wolfgang Schwarz +pixolino.com + +// Internet-Pro, LLP: https://netangels.ru/ +// Submited by Vasiliy Sheredeko +na4u.ru + +// iopsys software solutions AB : https://iopsys.eu/ +// Submitted by Roman Azarenko +iopsys.se + +// IPiFony Systems, Inc. : https://www.ipifony.com/ +// Submitted by Matthew Hardeman +ipifony.net + +// IServ GmbH : https://iserv.eu +// Submitted by Kim-Alexander Brodowski +mein-iserv.de +schulserver.de +test-iserv.de +iserv.dev + +// I-O DATA DEVICE, INC. : http://www.iodata.com/ +// Submitted by Yuji Minagawa +iobb.net + +// Jelastic, Inc. : https://jelastic.com/ +// Submited by Ihor Kolodyuk +mel.cloudlets.com.au +cloud.interhostsolutions.be +users.scale.virtualcloud.com.br +mycloud.by +alp1.ae.flow.ch +appengine.flow.ch +es-1.axarnet.cloud +diadem.cloud +vip.jelastic.cloud +jele.cloud +it1.eur.aruba.jenv-aruba.cloud +it1.jenv-aruba.cloud +it1-eur.jenv-arubabiz.cloud +oxa.cloud +tn.oxa.cloud +uk.oxa.cloud +primetel.cloud +uk.primetel.cloud +ca.reclaim.cloud +uk.reclaim.cloud +us.reclaim.cloud +ch.trendhosting.cloud +de.trendhosting.cloud +jele.club +clicketcloud.com +ams.cloudswitches.com +au.cloudswitches.com +sg.cloudswitches.com +dopaas.com +elastyco.com +nv.elastyco.com +hidora.com +paas.hosted-by-previder.com +rag-cloud.hosteur.com +rag-cloud-ch.hosteur.com +jcloud.ik-server.com +jcloud-ver-jpc.ik-server.com +demo.jelastic.com +kilatiron.com +paas.massivegrid.com +jed.wafaicloud.com +lon.wafaicloud.com +ryd.wafaicloud.com +j.scaleforce.com.cy +jelastic.dogado.eu +paas.leviracloud.eu +fi.cloudplatform.fi +demo.datacenter.fi +paas.datacenter.fi +jele.host +mircloud.host +jele.io +ocs.opusinteractive.io +cloud.unispace.io +cloud-de.unispace.io +cloud-fr1.unispace.io +jc.neen.it +cloud.jelastic.open.tim.it +jcloud.kz +upaas.kazteleport.kz +jl.serv.net.mx +cloudjiffy.net +fra1-de.cloudjiffy.net +west1-us.cloudjiffy.net +ams1.jls.docktera.net +jls-sto1.elastx.net +jls-sto2.elastx.net +jls-sto3.elastx.net +fr-1.paas.massivegrid.net +lon-1.paas.massivegrid.net +lon-2.paas.massivegrid.net +ny-1.paas.massivegrid.net +ny-2.paas.massivegrid.net +sg-1.paas.massivegrid.net +jelastic.saveincloud.net +nordeste-idc.saveincloud.net +j.scaleforce.net +jelastic.tsukaeru.net +atl.jelastic.vps-host.net +njs.jelastic.vps-host.net +unicloud.pl +mircloud.ru +jelastic.regruhosting.ru +enscaled.sg +jele.site +jelastic.team +orangecloud.tn +j.layershift.co.uk +phx.enscaled.us +mircloud.us + +// Jino : https://www.jino.ru +// Submitted by Sergey Ulyashin +myjino.ru +*.hosting.myjino.ru +*.landing.myjino.ru +*.spectrum.myjino.ru +*.vps.myjino.ru + +// Joyent : https://www.joyent.com/ +// Submitted by Brian Bennett +*.triton.zone +*.cns.joyent.com + +// JS.ORG : http://dns.js.org +// Submitted by Stefan Keim +js.org + +// KaasHosting : http://www.kaashosting.nl/ +// Submitted by Wouter Bakker +kaas.gg +khplay.nl + +// Keyweb AG : https://www.keyweb.de +// Submitted by Martin Dannehl +keymachine.de + +// KingHost : https://king.host +// Submitted by Felipe Keller Braz +kinghost.net +uni5.net + +// KnightPoint Systems, LLC : http://www.knightpoint.com/ +// Submitted by Roy Keene +knightpoint.systems + +// KUROKU LTD : https://kuroku.ltd/ +// Submitted by DisposaBoy +oya.to + +// .KRD : http://nic.krd/data/krd/Registration%20Policy.pdf +co.krd +edu.krd + +// LCube - Professional hosting e.K. : https://www.lcube-webhosting.de +// Submitted by Lars Laehn +git-repos.de +lcube-server.de +svn-repos.de + +// Leadpages : https://www.leadpages.net +// Submitted by Greg Dallavalle +leadpages.co +lpages.co +lpusercontent.com + +// Lelux.fi : https://lelux.fi/ +// Submitted by Lelux Admin +lelux.site + +// Lifetime Hosting : https://Lifetime.Hosting/ +// Submitted by Mike Fillator +co.business +co.education +co.events +co.financial +co.network +co.place +co.technology + +// Lightmaker Property Manager, Inc. : https://app.lmpm.com/ +// Submitted by Greg Holland +app.lmpm.com + +// linkyard ldt: https://www.linkyard.ch/ +// Submitted by Mario Siegenthaler +linkyard.cloud +linkyard-cloud.ch + +// Linode : https://linode.com +// Submitted by +members.linode.com +*.nodebalancer.linode.com +*.linodeobjects.com + +// LiquidNet Ltd : http://www.liquidnetlimited.com/ +// Submitted by Victor Velchev +we.bs + +// localzone.xyz +// Submitted by Kenny Niehage +localzone.xyz + +// Log'in Line : https://www.loginline.com/ +// Submitted by Rémi Mach +loginline.app +loginline.dev +loginline.io +loginline.services +loginline.site + +// LubMAN UMCS Sp. z o.o : https://lubman.pl/ +// Submitted by Ireneusz Maliszewski +krasnik.pl +leczna.pl +lubartow.pl +lublin.pl +poniatowa.pl +swidnik.pl + +// Lug.org.uk : https://lug.org.uk +// Submitted by Jon Spriggs +glug.org.uk +lug.org.uk +lugs.org.uk + +// Lukanet Ltd : https://lukanet.com +// Submitted by Anton Avramov +barsy.bg +barsy.co.uk +barsyonline.co.uk +barsycenter.com +barsyonline.com +barsy.club +barsy.de +barsy.eu +barsy.in +barsy.info +barsy.io +barsy.me +barsy.menu +barsy.mobi +barsy.net +barsy.online +barsy.org +barsy.pro +barsy.pub +barsy.shop +barsy.site +barsy.support +barsy.uk + +// Magento Commerce +// Submitted by Damien Tournoud +*.magentosite.cloud + +// May First - People Link : https://mayfirst.org/ +// Submitted by Jamie McClelland +mayfirst.info +mayfirst.org + +// Mail.Ru Group : https://hb.cldmail.ru +// Submitted by Ilya Zaretskiy +hb.cldmail.ru + +// mcpe.me : https://mcpe.me +// Submitted by Noa Heyl +mcpe.me + +// McHost : https://mchost.ru +// Submitted by Evgeniy Subbotin +mcdir.ru +vps.mcdir.ru + +// Memset hosting : https://www.memset.com +// Submitted by Tom Whitwell +miniserver.com +memset.net + +// MetaCentrum, CESNET z.s.p.o. : https://www.metacentrum.cz/en/ +// Submitted by Zdeněk Šustr +*.cloud.metacentrum.cz +custom.metacentrum.cz + +// MetaCentrum, CESNET z.s.p.o. : https://www.metacentrum.cz/en/ +// Submitted by Radim Janča +flt.cloud.muni.cz +usr.cloud.muni.cz + +// Meteor Development Group : https://www.meteor.com/hosting +// Submitted by Pierre Carrier +meteorapp.com +eu.meteorapp.com + +// Michau Enterprises Limited : http://www.co.pl/ +co.pl + +// Microsoft Corporation : http://microsoft.com +// Submitted by Mitch Webster +*.azurecontainer.io +azurewebsites.net +azure-mobile.net +cloudapp.net +azurestaticapps.net +centralus.azurestaticapps.net +eastasia.azurestaticapps.net +eastus2.azurestaticapps.net +westeurope.azurestaticapps.net +westus2.azurestaticapps.net + +// minion.systems : http://minion.systems +// Submitted by Robert Böttinger +csx.cc + +// MobileEducation, LLC : https://joinforte.com +// Submitted by Grayson Martin +forte.id + +// Mozilla Corporation : https://mozilla.com +// Submitted by Ben Francis +mozilla-iot.org + +// Mozilla Foundation : https://mozilla.org/ +// Submitted by glob +bmoattachments.org + +// MSK-IX : https://www.msk-ix.ru/ +// Submitted by Khannanov Roman +net.ru +org.ru +pp.ru + +// Mythic Beasts : https://www.mythic-beasts.com +// Submitted by Paul Cammish +hostedpi.com +customer.mythic-beasts.com +lynx.mythic-beasts.com +ocelot.mythic-beasts.com +onza.mythic-beasts.com +sphinx.mythic-beasts.com +vs.mythic-beasts.com +x.mythic-beasts.com +yali.mythic-beasts.com +cust.retrosnub.co.uk + +// Nabu Casa : https://www.nabucasa.com +// Submitted by Paulus Schoutsen +ui.nabu.casa + +// Names.of.London : https://names.of.london/ +// Submitted by James Stevens or +pony.club +of.fashion +in.london +of.london +from.marketing +with.marketing +for.men +repair.men +and.mom +for.mom +for.one +under.one +for.sale +that.win +from.work +to.work + +// NCTU.ME : https://nctu.me/ +// Submitted by Tocknicsu +nctu.me + +// Netlify : https://www.netlify.com +// Submitted by Jessica Parsons +netlify.app + +// Neustar Inc. +// Submitted by Trung Tran +4u.com + +// ngrok : https://ngrok.com/ +// Submitted by Alan Shreve +ngrok.io + +// Nimbus Hosting Ltd. : https://www.nimbushosting.co.uk/ +// Submitted by Nicholas Ford +nh-serv.co.uk + +// NFSN, Inc. : https://www.NearlyFreeSpeech.NET/ +// Submitted by Jeff Wheelhouse +nfshost.com + +// Now-DNS : https://now-dns.com +// Submitted by Steve Russell +dnsking.ch +mypi.co +n4t.co +001www.com +ddnslive.com +myiphost.com +forumz.info +16-b.it +32-b.it +64-b.it +soundcast.me +tcp4.me +dnsup.net +hicam.net +now-dns.net +ownip.net +vpndns.net +dynserv.org +now-dns.org +x443.pw +now-dns.top +ntdll.top +freeddns.us +crafting.xyz +zapto.xyz + +// nsupdate.info : https://www.nsupdate.info/ +// Submitted by Thomas Waldmann +nsupdate.info +nerdpol.ovh + +// No-IP.com : https://noip.com/ +// Submitted by Deven Reza +blogsyte.com +brasilia.me +cable-modem.org +ciscofreak.com +collegefan.org +couchpotatofries.org +damnserver.com +ddns.me +ditchyourip.com +dnsfor.me +dnsiskinky.com +dvrcam.info +dynns.com +eating-organic.net +fantasyleague.cc +geekgalaxy.com +golffan.us +health-carereform.com +homesecuritymac.com +homesecuritypc.com +hopto.me +ilovecollege.info +loginto.me +mlbfan.org +mmafan.biz +myactivedirectory.com +mydissent.net +myeffect.net +mymediapc.net +mypsx.net +mysecuritycamera.com +mysecuritycamera.net +mysecuritycamera.org +net-freaks.com +nflfan.org +nhlfan.net +no-ip.ca +no-ip.co.uk +no-ip.net +noip.us +onthewifi.com +pgafan.net +point2this.com +pointto.us +privatizehealthinsurance.net +quicksytes.com +read-books.org +securitytactics.com +serveexchange.com +servehumour.com +servep2p.com +servesarcasm.com +stufftoread.com +ufcfan.org +unusualperson.com +workisboring.com +3utilities.com +bounceme.net +ddns.net +ddnsking.com +gotdns.ch +hopto.org +myftp.biz +myftp.org +myvnc.com +no-ip.biz +no-ip.info +no-ip.org +noip.me +redirectme.net +servebeer.com +serveblog.net +servecounterstrike.com +serveftp.com +servegame.com +servehalflife.com +servehttp.com +serveirc.com +serveminecraft.net +servemp3.com +servepics.com +servequake.com +sytes.net +webhop.me +zapto.org + +// NodeArt : https://nodeart.io +// Submitted by Konstantin Nosov +stage.nodeart.io + +// Nodum B.V. : https://nodum.io/ +// Submitted by Wietse Wind +nodum.co +nodum.io + +// Nucleos Inc. : https://nucleos.com +// Submitted by Piotr Zduniak +pcloud.host + +// NYC.mn : http://www.information.nyc.mn +// Submitted by Matthew Brown +nyc.mn + +// NymNom : https://nymnom.com/ +// Submitted by NymNom +nom.ae +nom.af +nom.ai +nom.al +nym.by +nom.bz +nym.bz +nom.cl +nym.ec +nom.gd +nom.ge +nom.gl +nym.gr +nom.gt +nym.gy +nym.hk +nom.hn +nym.ie +nom.im +nom.ke +nym.kz +nym.la +nym.lc +nom.li +nym.li +nym.lt +nym.lu +nom.lv +nym.me +nom.mk +nym.mn +nym.mx +nom.nu +nym.nz +nym.pe +nym.pt +nom.pw +nom.qa +nym.ro +nom.rs +nom.si +nym.sk +nom.st +nym.su +nym.sx +nom.tj +nym.tw +nom.ug +nom.uy +nom.vc +nom.vg + +// Observable, Inc. : https://observablehq.com +// Submitted by Mike Bostock +static.observableusercontent.com + +// Octopodal Solutions, LLC. : https://ulterius.io/ +// Submitted by Andrew Sampson +cya.gg + +// OMG.LOL : +// Submitted by Adam Newbold +omg.lol + +// Omnibond Systems, LLC. : https://www.omnibond.com +// Submitted by Cole Estep +cloudycluster.net + +// OmniWe Limited: https://omniwe.com +// Submitted by Vicary Archangel +omniwe.site + +// One Fold Media : http://www.onefoldmedia.com/ +// Submitted by Eddie Jones +nid.io + +// Open Social : https://www.getopensocial.com/ +// Submitted by Alexander Varwijk +opensocial.site + +// OpenCraft GmbH : http://opencraft.com/ +// Submitted by Sven Marnach +opencraft.hosting + +// Opera Software, A.S.A. +// Submitted by Yngve Pettersen +operaunite.com + +// Oursky Limited : https://skygear.io/ +// Submited by Skygear Developer +skygearapp.com + +// OutSystems +// Submitted by Duarte Santos +outsystemscloud.com + +// OwnProvider GmbH: http://www.ownprovider.com +// Submitted by Jan Moennich +ownprovider.com +own.pm + +// OwO : https://whats-th.is/ +// Submitted by Dean Sheather +*.owo.codes + +// OX : http://www.ox.rs +// Submitted by Adam Grand +ox.rs + +// oy.lc +// Submitted by Charly Coste +oy.lc + +// Pagefog : https://pagefog.com/ +// Submitted by Derek Myers +pgfog.com + +// Pagefront : https://www.pagefronthq.com/ +// Submitted by Jason Kriss +pagefrontapp.com + +// PageXL : https://pagexl.com +// Submitted by Yann Guichard +pagexl.com + +// pcarrier.ca Software Inc: https://pcarrier.ca/ +// Submitted by Pierre Carrier +bar0.net +bar1.net +bar2.net +rdv.to + +// .pl domains (grandfathered) +art.pl +gliwice.pl +krakow.pl +poznan.pl +wroc.pl +zakopane.pl + +// Pantheon Systems, Inc. : https://pantheon.io/ +// Submitted by Gary Dylina +pantheonsite.io +gotpantheon.com + +// Peplink | Pepwave : http://peplink.com/ +// Submitted by Steve Leung +mypep.link + +// Perspecta : https://perspecta.com/ +// Submitted by Kenneth Van Alstyne +perspecta.cloud + +// PE Ulyanov Kirill Sergeevich : https://airy.host +// Submitted by Kirill Ulyanov +lk3.ru +ra-ru.ru +zsew.ru + +// Planet-Work : https://www.planet-work.com/ +// Submitted by Frédéric VANNIÈRE +on-web.fr + +// Platform.sh : https://platform.sh +// Submitted by Nikola Kotur +bc.platform.sh +ent.platform.sh +eu.platform.sh +us.platform.sh +*.platformsh.site + +// Platter: https://platter.dev +// Submitted by Patrick Flor +platter-app.com +platter-app.dev +platterp.us + +// Plesk : https://www.plesk.com/ +// Submitted by Anton Akhtyamov +pdns.page +plesk.page +pleskns.com + +// Port53 : https://port53.io/ +// Submitted by Maximilian Schieder +dyn53.io + +// Positive Codes Technology Company : http://co.bn/faq.html +// Submitted by Zulfais +co.bn + +// prgmr.com : https://prgmr.com/ +// Submitted by Sarah Newman +xen.prgmr.com + +// priv.at : http://www.nic.priv.at/ +// Submitted by registry +priv.at + +// privacytools.io : https://www.privacytools.io/ +// Submitted by Jonah Aragon +prvcy.page + +// Protocol Labs : https://protocol.ai/ +// Submitted by Michael Burns +*.dweb.link + +// Protonet GmbH : http://protonet.io +// Submitted by Martin Meier +protonet.io + +// Publication Presse Communication SARL : https://ppcom.fr +// Submitted by Yaacov Akiba Slama +chirurgiens-dentistes-en-france.fr +byen.site + +// pubtls.org: https://www.pubtls.org +// Submitted by Kor Nielsen +pubtls.org + +// QOTO, Org. +// Submitted by Jeffrey Phillips Freeman +qoto.io + +// Qualifio : https://qualifio.com/ +// Submitted by Xavier De Cock +qualifioapp.com + +// QuickBackend: https://www.quickbackend.com +// Submitted by Dani Biro +qbuser.com + +// Redstar Consultants : https://www.redstarconsultants.com/ +// Submitted by Jons Slemmer +instantcloud.cn + +// Russian Academy of Sciences +// Submitted by Tech Support +ras.ru + +// QA2 +// Submitted by Daniel Dent (https://www.danieldent.com/) +qa2.com + +// QCX +// Submitted by Cassandra Beelen +qcx.io +*.sys.qcx.io + +// QNAP System Inc : https://www.qnap.com +// Submitted by Nick Chang +dev-myqnapcloud.com +alpha-myqnapcloud.com +myqnapcloud.com + +// Quip : https://quip.com +// Submitted by Patrick Linehan +*.quipelements.com + +// Qutheory LLC : http://qutheory.io +// Submitted by Jonas Schwartz +vapor.cloud +vaporcloud.io + +// Rackmaze LLC : https://www.rackmaze.com +// Submitted by Kirill Pertsev +rackmaze.com +rackmaze.net + +// Rakuten Games, Inc : https://dev.viberplay.io +// Submitted by Joshua Zhang +g.vbrplsbx.io + +// Rancher Labs, Inc : https://rancher.com +// Submitted by Vincent Fiduccia +*.on-k3s.io +*.on-rancher.cloud +*.on-rio.io + +// Read The Docs, Inc : https://www.readthedocs.org +// Submitted by David Fischer +readthedocs.io + +// Red Hat, Inc. OpenShift : https://openshift.redhat.com/ +// Submitted by Tim Kramer +rhcloud.com + +// Render : https://render.com +// Submitted by Anurag Goel +app.render.com +onrender.com + +// Repl.it : https://repl.it +// Submitted by Mason Clayton +repl.co +repl.run + +// Resin.io : https://resin.io +// Submitted by Tim Perry +resindevice.io +devices.resinstaging.io + +// RethinkDB : https://www.rethinkdb.com/ +// Submitted by Chris Kastorff +hzc.io + +// Revitalised Limited : http://www.revitalised.co.uk +// Submitted by Jack Price +wellbeingzone.eu +wellbeingzone.co.uk + +// Rochester Institute of Technology : http://www.rit.edu/ +// Submitted by Jennifer Herting +git-pages.rit.edu + +// Sandstorm Development Group, Inc. : https://sandcats.io/ +// Submitted by Asheesh Laroia +sandcats.io + +// SBE network solutions GmbH : https://www.sbe.de/ +// Submitted by Norman Meilick +logoip.de +logoip.com + +// schokokeks.org GbR : https://schokokeks.org/ +// Submitted by Hanno Böck +schokokeks.net + +// Scottish Government: https://www.gov.scot +// Submitted by Martin Ellis +gov.scot + +// Scry Security : http://www.scrysec.com +// Submitted by Shante Adam +scrysec.com + +// Securepoint GmbH : https://www.securepoint.de +// Submitted by Erik Anders +firewall-gateway.com +firewall-gateway.de +my-gateway.de +my-router.de +spdns.de +spdns.eu +firewall-gateway.net +my-firewall.org +myfirewall.org +spdns.org + +// Seidat : https://www.seidat.com +// Submitted by Artem Kondratev +seidat.net + +// Senseering GmbH : https://www.senseering.de +// Submitted by Felix Mönckemeyer +senseering.net + +// Service Online LLC : http://drs.ua/ +// Submitted by Serhii Bulakh +biz.ua +co.ua +pp.ua + +// ShiftEdit : https://shiftedit.net/ +// Submitted by Adam Jimenez +shiftedit.io + +// Shopblocks : http://www.shopblocks.com/ +// Submitted by Alex Bowers +myshopblocks.com + +// Shopit : https://www.shopitcommerce.com/ +// Submitted by Craig McMahon +shopitsite.com + +// shopware AG : https://shopware.com +// Submitted by Jens Küper +shopware.store + +// Siemens Mobility GmbH +// Submitted by Oliver Graebner +mo-siemens.io + +// SinaAppEngine : http://sae.sina.com.cn/ +// Submitted by SinaAppEngine +1kapp.com +appchizi.com +applinzi.com +sinaapp.com +vipsinaapp.com + +// Siteleaf : https://www.siteleaf.com/ +// Submitted by Skylar Challand +siteleaf.net + +// Skyhat : http://www.skyhat.io +// Submitted by Shante Adam +bounty-full.com +alpha.bounty-full.com +beta.bounty-full.com + +// Small Technology Foundation : https://small-tech.org +// Submitted by Aral Balkan +small-web.org + +// Stackhero : https://www.stackhero.io +// Submitted by Adrien Gillon +stackhero-network.com + +// staticland : https://static.land +// Submitted by Seth Vincent +static.land +dev.static.land +sites.static.land + +// Sony Interactive Entertainment LLC : https://sie.com/ +// Submitted by David Coles +playstation-cloud.com + +// SourceLair PC : https://www.sourcelair.com +// Submitted by Antonis Kalipetis +apps.lair.io +*.stolos.io + +// SpaceKit : https://www.spacekit.io/ +// Submitted by Reza Akhavan +spacekit.io + +// SpeedPartner GmbH: https://www.speedpartner.de/ +// Submitted by Stefan Neufeind +customer.speedpartner.de + +// Standard Library : https://stdlib.com +// Submitted by Jacob Lee +api.stdlib.com + +// Storj Labs Inc. : https://storj.io/ +// Submitted by Philip Hutchins +storj.farm + +// Studenten Net Twente : http://www.snt.utwente.nl/ +// Submitted by Silke Hofstra +utwente.io + +// Student-Run Computing Facility : https://www.srcf.net/ +// Submitted by Edwin Balani +soc.srcf.net +user.srcf.net + +// Sub 6 Limited: http://www.sub6.com +// Submitted by Dan Miller +temp-dns.com + +// Swisscom Application Cloud: https://developer.swisscom.com +// Submitted by Matthias.Winzeler +applicationcloud.io +scapp.io + +// Symfony, SAS : https://symfony.com/ +// Submitted by Fabien Potencier +*.s5y.io +*.sensiosite.cloud + +// Syncloud : https://syncloud.org +// Submitted by Boris Rybalkin +syncloud.it + +// Synology, Inc. : https://www.synology.com/ +// Submitted by Rony Weng +diskstation.me +dscloud.biz +dscloud.me +dscloud.mobi +dsmynas.com +dsmynas.net +dsmynas.org +familyds.com +familyds.net +familyds.org +i234.me +myds.me +synology.me +vpnplus.to +direct.quickconnect.to + +// TAIFUN Software AG : http://taifun-software.de +// Submitted by Bjoern Henke +taifun-dns.de + +// TASK geographical domains (www.task.gda.pl/uslugi/dns) +gda.pl +gdansk.pl +gdynia.pl +med.pl +sopot.pl + +// Teckids e.V. : https://www.teckids.org +// Submitted by Dominik George +edugit.org + +// Telebit : https://telebit.cloud +// Submitted by AJ ONeal +telebit.app +telebit.io +*.telebit.xyz + +// The Gwiddle Foundation : https://gwiddlefoundation.org.uk +// Submitted by Joshua Bayfield +gwiddle.co.uk + +// Thingdust AG : https://thingdust.com/ +// Submitted by Adrian Imboden +thingdustdata.com +cust.dev.thingdust.io +cust.disrec.thingdust.io +cust.prod.thingdust.io +cust.testing.thingdust.io +*.firenet.ch +*.svc.firenet.ch + +// Tlon.io : https://tlon.io +// Submitted by Mark Staarink +arvo.network +azimuth.network +tlon.network + +// TownNews.com : http://www.townnews.com +// Submitted by Dustin Ward +bloxcms.com +townnews-staging.com + +// TrafficPlex GmbH : https://www.trafficplex.de/ +// Submitted by Phillipp Röll +12hp.at +2ix.at +4lima.at +lima-city.at +12hp.ch +2ix.ch +4lima.ch +lima-city.ch +trafficplex.cloud +de.cool +12hp.de +2ix.de +4lima.de +lima-city.de +1337.pictures +clan.rip +lima-city.rocks +webspace.rocks +lima.zone + +// TransIP : https://www.transip.nl +// Submitted by Rory Breuk +*.transurl.be +*.transurl.eu +*.transurl.nl + +// TuxFamily : http://tuxfamily.org +// Submitted by TuxFamily administrators +tuxfamily.org + +// TwoDNS : https://www.twodns.de/ +// Submitted by TwoDNS-Support +dd-dns.de +diskstation.eu +diskstation.org +dray-dns.de +draydns.de +dyn-vpn.de +dynvpn.de +mein-vigor.de +my-vigor.de +my-wan.de +syno-ds.de +synology-diskstation.de +synology-ds.de + +// Uberspace : https://uberspace.de +// Submitted by Moritz Werner +uber.space +*.uberspace.de + +// UDR Limited : http://www.udr.hk.com +// Submitted by registry +hk.com +hk.org +ltd.hk +inc.hk + +// United Gameserver GmbH : https://united-gameserver.de +// Submitted by Stefan Schwarz +virtualuser.de +virtual-user.de + +// urown.net : https://urown.net +// Submitted by Hostmaster +urown.cloud +dnsupdate.info + +// .US +// Submitted by Ed Moore +lib.de.us + +// VeryPositive SIA : http://very.lv +// Submitted by Danko Aleksejevs +2038.io + +// Vercel, Inc : https://vercel.com/ +// Submitted by Connor Davis +vercel.app +vercel.dev +now.sh + +// Viprinet Europe GmbH : http://www.viprinet.com +// Submitted by Simon Kissel +router.management + +// Virtual-Info : https://www.virtual-info.info/ +// Submitted by Adnan RIHAN +v-info.info + +// Voorloper.com: https://voorloper.com +// Submitted by Nathan van Bakel +voorloper.cloud + +// Voxel.sh DNS : https://voxel.sh/dns/ +// Submitted by Mia Rehlinger +neko.am +nyaa.am +be.ax +cat.ax +es.ax +eu.ax +gg.ax +mc.ax +us.ax +xy.ax +nl.ci +xx.gl +app.gp +blog.gt +de.gt +to.gt +be.gy +cc.hn +blog.kg +io.kg +jp.kg +tv.kg +uk.kg +us.kg +de.ls +at.md +de.md +jp.md +to.md +uwu.nu +indie.porn +vxl.sh +ch.tc +me.tc +we.tc +nyan.to +at.vg +blog.vu +dev.vu +me.vu + +// V.UA Domain Administrator : https://domain.v.ua/ +// Submitted by Serhii Rostilo +v.ua + +// Waffle Computer Inc., Ltd. : https://docs.waffleinfo.com +// Submitted by Masayuki Note +wafflecell.com + +// WapBlog.ID : https://www.wapblog.id +// Submitted by Fajar Sodik +idnblogger.com +indowapblog.com +bloger.id +wblog.id +wbq.me +fastblog.net + +// WebHare bv: https://www.webhare.com/ +// Submitted by Arnold Hendriks +*.webhare.dev + +// WeDeploy by Liferay, Inc. : https://www.wedeploy.com +// Submitted by Henrique Vicente +wedeploy.io +wedeploy.me +wedeploy.sh + +// Western Digital Technologies, Inc : https://www.wdc.com +// Submitted by Jung Jin +remotewd.com + +// WIARD Enterprises : https://wiardweb.com +// Submitted by Kidd Hustle +pages.wiardweb.com + +// Wikimedia Labs : https://wikitech.wikimedia.org +// Submitted by Arturo Borrero Gonzalez +wmflabs.org +toolforge.org +wmcloud.org + +// WISP : https://wisp.gg +// Submitted by Stepan Fedotov +panel.gg +daemon.panel.gg + +// WoltLab GmbH : https://www.woltlab.com +// Submitted by Tim Düsterhus +myforum.community +community-pro.de +diskussionsbereich.de +community-pro.net +meinforum.net + +// www.com.vc : http://www.com.vc +// Submitted by Li Hui +cn.vu + +// XenonCloud GbR: https://xenoncloud.net +// Submitted by Julian Uphoff +half.host + +// XnBay Technology : http://www.xnbay.com/ +// Submitted by XnBay Developer +xnbay.com +u2.xnbay.com +u2-local.xnbay.com + +// XS4ALL Internet bv : https://www.xs4all.nl/ +// Submitted by Daniel Mostertman +cistron.nl +demon.nl +xs4all.space + +// Yandex.Cloud LLC: https://cloud.yandex.com +// Submitted by Alexander Lodin +yandexcloud.net +storage.yandexcloud.net +website.yandexcloud.net + +// YesCourse Pty Ltd : https://yescourse.com +// Submitted by Atul Bhouraskar +official.academy + +// Yola : https://www.yola.com/ +// Submitted by Stefano Rivera +yolasite.com + +// Yombo : https://yombo.net +// Submitted by Mitch Schwenk +ybo.faith +yombo.me +homelink.one +ybo.party +ybo.review +ybo.science +ybo.trade + +// Yunohost : https://yunohost.org +// Submitted by Valentin Grimaud +nohost.me +noho.st + +// ZaNiC : http://www.za.net/ +// Submitted by registry +za.net +za.org + +// Zine EOOD : https://zine.bg/ +// Submitted by Martin Angelov +bss.design + +// Zitcom A/S : https://www.zitcom.dk +// Submitted by Emil Stahl +basicserver.io +virtualserver.io +enterprisecloud.nu + +// Mintere : https://mintere.com/ +// Submitted by Ben Aubin +mintere.site + +// Cityhost LLC : https://cityhost.ua +// Submitted by Maksym Rivtin +cx.ua + +// WP Engine : https://wpengine.com/ +// Submitted by Michael Smith +// Submitted by Brandon DuRette +wpenginepowered.com +js.wpenginepowered.com + +// Impertrix Solutions : +// Submitted by Zhixiang Zhao +impertrixcdn.com +impertrix.com + +// GignoSystemJapan: http://gsj.bz +// Submitted by GignoSystemJapan +gsj.bz +// ===END PRIVATE DOMAINS=== From 2396d2224af53c7779c12caf9cbce049703c0ed4 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 24 Nov 2020 14:10:10 -0500 Subject: [PATCH 20/42] fix for issue --- .../autopsy/coreutils/DomainCategorizer.java | 53 ++++--------------- .../autopsy/coreutils/NetworkUtils.java | 48 +++++++++++++++-- 2 files changed, 53 insertions(+), 48 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/DomainCategorizer.java b/Core/src/org/sleuthkit/autopsy/coreutils/DomainCategorizer.java index 63b1a07b47..3a51578609 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/DomainCategorizer.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/DomainCategorizer.java @@ -24,8 +24,6 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.HashMap; import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.commons.lang3.StringUtils; @@ -134,53 +132,22 @@ class DomainCategorizer { } } - // based on syntax shown here: https://en.wikipedia.org/wiki/URL - // and intially based on regex provided here: https://stackoverflow.com/a/9608008 - Pattern pattern = Pattern.compile("^\\s*(?:[^:\\/?#]+:)?(?:\\/\\/)?(?:[^\\/?#@]*@)?([^:\\/?#]*)"); - - /** - * Sanitizes a url string so that just the host is extracted ignoring - * scheme, userinfo, port, and path if present. - * - * @param url The url-like string. - * @return The host removing port, user info, scheme, and path - */ - private String sanitizedHost(String url) { - if (StringUtils.isBlank(url)) { - return null; - } - - Matcher m = pattern.matcher(url); - if (m.find()) { - return m.group(1); - } else { - return null; - } - } - /** * Gets the domain by attempting to identify the host without the subdomain. - * If no host can be determined, the full parameter is returned. If no - * domain can be determined, the host is returned. + * If no domain can be determined, the domain is returned. * - * @param url The url/domain to query for. - * @return If provided argument is blank, null is returned. If no host can - * be determined the 'domain' parameter is returned. If no domain suffixes - * can be identified, the full host is returned. If a host and suffixes are - * identified, the domain (all suffixes with a prefix of the next token) are - * returned. + * @param domain The domain to query for. + * @return If provided argument is blank, null is returned. If no domain + * suffixes can be identified, the full host is returned. If a host and + * suffixes are identified, the domain (all suffixes with a prefix of the + * next token) are returned. */ - String getDomain(String url) { - if (StringUtils.isBlank(url)) { + String getDomain(String domain) { + if (StringUtils.isBlank(domain)) { return null; } - String host = sanitizedHost(url); - if (host == null) { - return url; - } - - List tokens = Stream.of(host.split(DELIMITER)) + List tokens = Stream.of(domain.split(DELIMITER)) .filter(StringUtils::isNotBlank) .collect(Collectors.toList()); @@ -196,7 +163,7 @@ class DomainCategorizer { // if first suffix cannot be found, return the whole domain if (idx == tokens.size() - 1) { - return host; + return domain; } else { int minIndex = Math.max(0, idx); List subList = tokens.subList(minIndex, tokens.size()); diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/NetworkUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/NetworkUtils.java index 2b9249d278..996bdb6744 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/NetworkUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/NetworkUtils.java @@ -22,7 +22,9 @@ import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.net.UnknownHostException; +import java.util.StringTokenizer; import java.util.logging.Level; +import org.openide.util.Exceptions; public class NetworkUtils { @@ -53,6 +55,46 @@ public class NetworkUtils { return hostName; } + /** + * Attempt to manually extract the domain from a URL. + * + * @param url + * @return empty string if no domain could be found + */ + private static String getBaseDomain(String url) { + String host = null; + + //strip protocol + String cleanUrl = url.replaceFirst(".*:\\/\\/", ""); + + //strip after slashes + String dirToks[] = cleanUrl.split("\\/"); + if (dirToks.length > 0) { + host = dirToks[0]; + } else { + host = cleanUrl; + } + + String base = host; + try { + base = DomainCategorizer.getInstance().getDomain(host); + } catch (IOException ex) { + logger.log(Level.WARNING, "Unable to load resources for domain categorization.", ex); + } + + // verify there are no special characters in there + if (base.matches(".*[~`!@#$%^&\\*\\(\\)\\+={}\\[\\];:\\?<>,/ ].*")) { + return ""; + } + + //verify that the base domain actually has a '.', details JIRA-4609 + if (!base.contains(".")) { + return ""; + } + + return base; + } + /** * Attempt to extract the domain from a URL. Will start by using the * built-in URL class, and if that fails will try to extract it manually. @@ -75,11 +117,7 @@ public class NetworkUtils { //was not a valid URL, try a less picky method if (result == null || result.trim().isEmpty()) { - try { - return DomainCategorizer.getInstance().getDomain(urlString); - } catch (IOException ex) { - logger.log(Level.SEVERE, "Unable to load resources for domain categorization.", ex); - } + return getBaseDomain(urlString); } return result; } From 95b9e51362c08033b5502f232ab6e383869e7bc8 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 24 Nov 2020 14:29:51 -0500 Subject: [PATCH 21/42] formatting --- Core/src/org/sleuthkit/autopsy/coreutils/NetworkUtils.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/NetworkUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/NetworkUtils.java index 996bdb6744..1f22c672ef 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/NetworkUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/NetworkUtils.java @@ -22,9 +22,7 @@ import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.net.UnknownHostException; -import java.util.StringTokenizer; import java.util.logging.Level; -import org.openide.util.Exceptions; public class NetworkUtils { From 37756a5f908fcfc0bc4c48d9c1dd9eed0d9469ee Mon Sep 17 00:00:00 2001 From: apriestman Date: Wed, 25 Nov 2020 08:00:10 -0500 Subject: [PATCH 22/42] Review --- .../sleuthkit/autopsy/geolocation/MapPanel.java | 16 +++++++++++----- .../autopsy/geolocation/datamodel/Area.java | 6 ------ .../autopsy/geolocation/datamodel/GeoPath.java | 10 ++++++++-- .../autopsy/geolocation/datamodel/Track.java | 5 ----- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/MapPanel.java b/Core/src/org/sleuthkit/autopsy/geolocation/MapPanel.java index 5f84a434e1..b9a40afad0 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/MapPanel.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/MapPanel.java @@ -905,8 +905,6 @@ final public class MapPanel extends javax.swing.JPanel { int lastY = 0; boolean first = true; - - GeneralPath polygon = new GeneralPath(GeneralPath.WIND_EVEN_ODD, track.size()); for (MapWaypoint wp : track) { Point2D p = map.getTileFactory().geoToPixel(wp.getPosition(), map.getZoom()); @@ -955,6 +953,13 @@ final public class MapPanel extends javax.swing.JPanel { this.areas = areas; } + /** + * Shade in the area on the map. + * + * @param area The waypoints defining the outline of the area. + * @param g Graphics2D + * @param map JXMapViewer + */ private void drawArea(Set area, Graphics2D g, JXMapViewer map) { if (area.isEmpty()) { return; @@ -978,9 +983,10 @@ final public class MapPanel extends javax.swing.JPanel { polygon.closePath(); Color areaColor = area.iterator().next().getColor(); - g.setPaint(new Color((float)(areaColor.getRed() / 255.0), - (float)(areaColor.getGreen() / 255.0), - (float)(areaColor.getBlue() / 255.0), + final double maxColorValue = 255.0; + g.setPaint(new Color((float)(areaColor.getRed() / maxColorValue), + (float)(areaColor.getGreen() / maxColorValue), + (float)(areaColor.getBlue() / maxColorValue), .2f)); g.fill(polygon); g.draw(polygon); diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Area.java b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Area.java index 021cc91e70..65b2f84362 100644 --- a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Area.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Area.java @@ -22,21 +22,17 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.logging.Level; import org.openide.util.NbBundle.Messages; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.blackboardutils.attributes.BlackboardJsonAttrUtil; import org.sleuthkit.datamodel.blackboardutils.attributes.BlackboardJsonAttrUtil.InvalidJsonException; import org.sleuthkit.datamodel.blackboardutils.attributes.GeoAreaPoints; -import org.sleuthkit.autopsy.coreutils.Logger; /** * A GPS track with which wraps the TSK_GPS_AREA artifact. */ public final class Area extends GeoPath { - private static final Logger LOGGER = Logger.getLogger(Track.class.getName()); - /** * Construct a new Area for the given artifact. * @@ -108,14 +104,12 @@ public final class Area extends GeoPath { private GeoAreaPoints getPointsList(Map attributeMap) throws GeoLocationDataException { BlackboardAttribute attribute = attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_AREAPOINTS); if (attribute == null) { - LOGGER.log(Level.SEVERE, "No TSK_GEO_AREAPOINTS attribute was present on the artifact."); throw new GeoLocationDataException("No TSK_GEO_AREAPOINTS attribute present in attribute map to parse."); } try { return BlackboardJsonAttrUtil.fromAttribute(attribute, GeoAreaPoints.class); } catch (InvalidJsonException ex) { - LOGGER.log(Level.SEVERE, "TSK_GEO_AREAPOINTS could not be properly parsed from TSK_GEO_AREAPOINTS attribute."); throw new GeoLocationDataException("Unable to parse area points in TSK_GEO_AREAPOINTS attribute", ex); } } diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoPath.java b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoPath.java index 37d655d166..4afbd922d0 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoPath.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoPath.java @@ -22,6 +22,8 @@ package org.sleuthkit.autopsy.geolocation.datamodel; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.logging.Level; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.SleuthkitCase; @@ -31,6 +33,8 @@ import org.sleuthkit.datamodel.TskCoreException; * Class representing a series of waypoints that form a path. */ public class GeoPath { + private static final Logger LOGGER = Logger.getLogger(GeoPath.class.getName()); + private final List waypointList; private final String pathName; private final BlackboardArtifact artifact; @@ -85,6 +89,7 @@ public class GeoPath { tracks.add(new Track(artifact)); } catch (GeoLocationDataException e) { + LOGGER.log(Level.WARNING, "Error loading track from artifact with ID " + artifact.getArtifactID(), e); allParsedSuccessfully = false; } } @@ -108,7 +113,7 @@ public class GeoPath { * @throws GeoLocationDataException */ public static GeoLocationParseResult getAreas(SleuthkitCase skCase, List sourceList) throws GeoLocationDataException { - List artifacts = null; + List artifacts; boolean allParsedSuccessfully = true; List areas = new ArrayList<>(); try { @@ -119,6 +124,7 @@ public class GeoPath { areas.add(new Area(artifact)); } catch (GeoLocationDataException e) { + LOGGER.log(Level.WARNING, "Error loading track from artifact with ID " + artifact.getArtifactID(), e); allParsedSuccessfully = false; } } @@ -126,7 +132,7 @@ public class GeoPath { } catch (TskCoreException ex) { throw new GeoLocationDataException("Unable to get artifacts for type: TSK_GPS_BOOKMARK", ex); } - return new GeoLocationParseResult(areas, allParsedSuccessfully); + return new GeoLocationParseResult<>(areas, allParsedSuccessfully); } /** diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Track.java b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Track.java index af19623100..24432ee62d 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Track.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Track.java @@ -22,20 +22,17 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.logging.Level; import org.openide.util.NbBundle.Messages; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.blackboardutils.attributes.BlackboardJsonAttrUtil; import org.sleuthkit.datamodel.blackboardutils.attributes.BlackboardJsonAttrUtil.InvalidJsonException; import org.sleuthkit.datamodel.blackboardutils.attributes.GeoTrackPoints; -import org.sleuthkit.autopsy.coreutils.Logger; /** * A GPS track with which wraps the TSK_GPS_TRACK artifact. */ public final class Track extends GeoPath { - private static final Logger LOGGER = Logger.getLogger(Track.class.getName()); private final Long startTimestamp; private final Long endTimeStamp; @@ -134,14 +131,12 @@ public final class Track extends GeoPath { private GeoTrackPoints getPointsList(Map attributeMap) throws GeoLocationDataException { BlackboardAttribute attribute = attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_TRACKPOINTS); if (attribute == null) { - LOGGER.log(Level.SEVERE, "No TSK_GEO_TRACKPOINTS attribute was present on the artifact."); throw new GeoLocationDataException("No TSK_GEO_TRACKPOINTS attribute present in attribute map to parse."); } try { return BlackboardJsonAttrUtil.fromAttribute(attribute, GeoTrackPoints.class); } catch (InvalidJsonException ex) { - LOGGER.log(Level.SEVERE, "TSK_GEO_TRACKPOINTS could not be properly parsed from TSK_GEO_TRACKPOINTS attribute."); throw new GeoLocationDataException("Unable to parse track points in TSK_GEO_TRACKPOINTS attribute", ex); } } From 217a5bab6e96351f98f7fe1ec5eb6dd9575a06ee Mon Sep 17 00:00:00 2001 From: apriestman Date: Mon, 30 Nov 2020 14:07:04 -0500 Subject: [PATCH 23/42] Add report button to health monitor. Add username column to health monitor database. --- .../autopsy/core/UserPreferences.java | 19 +++ .../healthmonitor/Bundle.properties-MERGED | 4 + .../autopsy/healthmonitor/HealthMonitor.java | 50 ++++++- .../healthmonitor/HealthMonitorDashboard.java | 139 +++++++++++++++++- 4 files changed, 202 insertions(+), 10 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java index 08c6f8f6d4..9738a01365 100644 --- a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java +++ b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java @@ -85,6 +85,7 @@ public final class UserPreferences { private static final String GEO_OSM_TILE_ZIP_PATH = "GeolocationOsmZipPath"; private static final String GEO_OSM_SERVER_ADDRESS = "GeolocationOsmServerAddress"; private static final String GEO_MBTILES_FILE_PATH = "GeolcoationMBTilesFilePath"; + private static final String HEALTH_MONITOR_REPORT_PATH = "HealthMonitorReportPath"; // Prevent instantiation. private UserPreferences() { @@ -632,4 +633,22 @@ public final class UserPreferences { return Paths.get(UserMachinePreferences.getBaseTempDirectory(), getAppName()) .toAbsolutePath().toString(); } + + /** + * Set the last used health monitor report path. + * + * @param reportPath Last used health monitor report path. + */ + public static void setHealthMonitorReportPath(String reportPath) { + preferences.put(HEALTH_MONITOR_REPORT_PATH, reportPath); + } + + /** + * Gets the last used health monitor report path. + * + * @return Last used health monitor report path. Empty string if no value has been recorded. + */ + public static String getHealthMonitorReportPath() { + return preferences.get(HEALTH_MONITOR_REPORT_PATH, ""); + } } \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/healthmonitor/Bundle.properties-MERGED index 5a7e3390f9..036466d2d4 100755 --- a/Core/src/org/sleuthkit/autopsy/healthmonitor/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/Bundle.properties-MERGED @@ -7,6 +7,10 @@ HealthMonitorDashboard.createTimingControlPanel.skipOutliers=Do not plot outlier HealthMonitorDashboard.createTimingPanel.noData=No data to display - monitor is not enabled HealthMonitorDashboard.createTimingPanel.timingMetricsTitle=Timing Metrics HealthMonitorDashboard.createUserControlPanel.maxDays=Max days to display +# {0} - Report file name +HealthMonitorDashboard.createUserControlPanel.reportDone=Report saved to: {0} +HealthMonitorDashboard.createUserControlPanel.reportError=Error generating report +HealthMonitorDashboard.createUserControlPanel.userReportButton=Generate Report HealthMonitorDashboard.createUserPanel.noData=No data to display - monitor is not enabled HealthMonitorDashboard.createUserPanel.userMetricsTitle=User Metrics HealthMonitorDashboard.DateRange.oneDay=One day diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitor.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitor.java index 4e100facb1..c5c457c81b 100644 --- a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitor.java @@ -65,7 +65,7 @@ public final class HealthMonitor implements PropertyChangeListener { private final static Logger logger = Logger.getLogger(HealthMonitor.class.getName()); private final static String DATABASE_NAME = "HealthMonitor"; private final static long DATABASE_WRITE_INTERVAL = 60; // Minutes - private final static CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION = new CaseDbSchemaVersionNumber(1, 1); + private final static CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION = new CaseDbSchemaVersionNumber(1, 2); private final static AtomicBoolean isEnabled = new AtomicBoolean(false); private static HealthMonitor instance; @@ -77,6 +77,7 @@ public final class HealthMonitor implements PropertyChangeListener { private BasicDataSource connectionPool = null; private CaseDbConnectionInfo connectionSettingsInUse = null; private String hostName; + private final String username; private HealthMonitor() throws HealthMonitorException { @@ -96,6 +97,9 @@ public final class HealthMonitor implements PropertyChangeListener { hostName = UUID.randomUUID().toString(); logger.log(Level.SEVERE, "Unable to look up host name - falling back to UUID " + hostName, ex); } + + // Get the user name + username = System.getProperty("user.name"); // Read from the database to determine if the module is enabled updateFromGlobalEnabledStatus(); @@ -197,6 +201,14 @@ public final class HealthMonitor implements PropertyChangeListener { + "case_name text NOT NULL" + ")"); } + + // Upgrade from 1.1 to 1.2 + // Changes: username added to user_data table + if (currentSchema.compareTo(new CaseDbSchemaVersionNumber(1, 2)) < 0) { + + // Add the user_data table + statement.execute("ALTER TABLE user_data ADD COLUMN username text"); + } // Update the schema version statement.execute("UPDATE db_info SET value='" + CURRENT_DB_SCHEMA_VERSION.getMajor() + "' WHERE name='SCHEMA_VERSION'"); @@ -499,7 +511,7 @@ public final class HealthMonitor implements PropertyChangeListener { // Add metrics to the database String addTimingInfoSql = "INSERT INTO timing_data (name, host, timestamp, count, average, max, min) VALUES (?, ?, ?, ?, ?, ?, ?)"; - String addUserInfoSql = "INSERT INTO user_data (host, timestamp, event_type, is_examiner, case_name) VALUES (?, ?, ?, ?, ?)"; + String addUserInfoSql = "INSERT INTO user_data (host, username, timestamp, event_type, is_examiner, case_name) VALUES (?, ?, ?, ?, ?, ?)"; try (PreparedStatement timingStatement = conn.prepareStatement(addTimingInfoSql); PreparedStatement userStatement = conn.prepareStatement(addUserInfoSql)) { @@ -519,10 +531,11 @@ public final class HealthMonitor implements PropertyChangeListener { for (UserData userInfo : userDataCopy) { userStatement.setString(1, hostName); - userStatement.setLong(2, userInfo.getTimestamp()); - userStatement.setInt(3, userInfo.getEventType().getEventValue()); - userStatement.setBoolean(4, userInfo.isExaminerNode()); - userStatement.setString(5, userInfo.getCaseName()); + userStatement.setString(2, username); + userStatement.setLong(3, userInfo.getTimestamp()); + userStatement.setInt(4, userInfo.getEventType().getEventValue()); + userStatement.setBoolean(5, userInfo.isExaminerNode()); + userStatement.setString(6, userInfo.getCaseName()); userStatement.execute(); } @@ -903,7 +916,8 @@ public final class HealthMonitor implements PropertyChangeListener { + "timestamp bigint NOT NULL," + "event_type int NOT NULL," + "is_examiner BOOLEAN NOT NULL," - + "case_name text NOT NULL" + + "case_name text NOT NULL," + + "username text" + ")"); statement.execute("INSERT INTO db_info (name, value) VALUES ('SCHEMA_VERSION', '" + CURRENT_DB_SCHEMA_VERSION.getMajor() + "')"); @@ -1340,12 +1354,13 @@ public final class HealthMonitor implements PropertyChangeListener { * Class holding user metric data. Can be used for storing new events or * retrieving events out of the database. */ - static class UserData { + static class UserData implements Comparable { private final UserEvent eventType; private long timestamp; private final boolean isExaminer; private final String hostname; + private String username; private String caseName; /** @@ -1359,6 +1374,7 @@ public final class HealthMonitor implements PropertyChangeListener { this.timestamp = System.currentTimeMillis(); this.isExaminer = (UserPreferences.SelectedMode.STANDALONE == UserPreferences.getMode()); this.hostname = ""; + this.username = ""; // If there's a case open, record the name try { @@ -1383,6 +1399,10 @@ public final class HealthMonitor implements PropertyChangeListener { this.eventType = UserEvent.valueOf(resultSet.getInt("event_type")); this.isExaminer = resultSet.getBoolean("is_examiner"); this.caseName = resultSet.getString("case_name"); + this.username = resultSet.getString("username"); + if (this.username == null) { + this.username = ""; + } } /** @@ -1443,6 +1463,20 @@ public final class HealthMonitor implements PropertyChangeListener { String getCaseName() { return caseName; } + + /** + * Get the user name for this metric + * + * @return the user name. Will be the empty string for older data. + */ + String getUserName() { + return username; + } + + @Override + public int compareTo(UserData otherData) { + return Long.compare(getTimestamp(), otherData.getTimestamp()); + } } /** diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorDashboard.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorDashboard.java index 477fa3b957..5125f8f005 100644 --- a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorDashboard.java +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorDashboard.java @@ -24,12 +24,17 @@ import java.awt.Dimension; import java.util.Set; import java.util.HashSet; import java.util.HashMap; +import java.util.Map; import java.util.Arrays; import java.util.ArrayList; import java.util.List; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.io.BufferedWriter; import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; import javax.swing.Box; import javax.swing.JButton; import javax.swing.JDialog; @@ -40,13 +45,19 @@ import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.BorderFactory; -import java.util.Map; import javax.swing.BoxLayout; import java.awt.GridLayout; +import java.nio.charset.StandardCharsets; import java.nio.file.Paths; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Collections; import java.util.logging.Level; import java.util.stream.Collectors; +import javax.swing.JFileChooser; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.PlatformUtil; @@ -443,7 +454,11 @@ public class HealthMonitorDashboard { * Create the panel with controls for the user panel * @return the control panel */ - @NbBundle.Messages({"HealthMonitorDashboard.createUserControlPanel.maxDays=Max days to display"}) + @NbBundle.Messages({"HealthMonitorDashboard.createUserControlPanel.maxDays=Max days to display", + "HealthMonitorDashboard.createUserControlPanel.userReportButton=Generate Report", + "HealthMonitorDashboard.createUserControlPanel.reportError=Error generating report", + "# {0} - Report file name", + "HealthMonitorDashboard.createUserControlPanel.reportDone=Report saved to: {0}"}) private JPanel createUserControlPanel() { JPanel userControlPanel = new JPanel(); @@ -473,9 +488,129 @@ public class HealthMonitorDashboard { userControlPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createUserControlPanel_maxDays())); userControlPanel.add(userDateComboBox); + // Create a button to create a user report + JButton reportButton = new JButton(Bundle.HealthMonitorDashboard_createUserControlPanel_userReportButton()); + + // Set up a listener on the report button + reportButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + JFileChooser reportFileChooser = new JFileChooser(); + reportFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + reportFileChooser.setCurrentDirectory(new File(UserPreferences.getHealthMonitorReportPath())); + final DateFormat csvTimestampFormat = new SimpleDateFormat("yyyyMMdd_HHmmss"); + String fileName = "UserReport_" + csvTimestampFormat.format(new Date())+ ".csv"; + reportFileChooser.setSelectedFile(new File(fileName)); + + int returnVal = reportFileChooser.showSaveDialog(userControlPanel); + if (returnVal == JFileChooser.APPROVE_OPTION) { + + File selectedFile = reportFileChooser.getSelectedFile(); + UserPreferences.setHealthMonitorReportPath(selectedFile.getParent()); + try { + generateCSVUserReport(selectedFile); + MessageNotifyUtil.Message.info(Bundle.HealthMonitorDashboard_createUserControlPanel_reportDone(selectedFile.getAbsoluteFile())); + } catch (HealthMonitorException ex) { + logger.log(Level.SEVERE, "Error generating report", ex); + MessageNotifyUtil.Message.error(Bundle.HealthMonitorDashboard_createUserControlPanel_reportError()); + } + } + } + }); + userControlPanel.add(reportButton); + return userControlPanel; } + /** + * Generate a csv report for the last week of user data. + * + * @param reportFile + * + * @throws HealthMonitorException + */ + private void generateCSVUserReport(File reportFile) throws HealthMonitorException { + final DateFormat timestampFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); + + try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(reportFile), StandardCharsets.UTF_8))) { + // Write header + writer.write("Case open,Case close,Duration,Host,User,Case name"); + writer.newLine(); + + // Get the list of user data sorted by timestamp + List dataForReport = HealthMonitor.getInstance().getUserMetricsFromDatabase(DateRange.ONE_WEEK.getTimestampRange()); + Collections.sort(dataForReport); + + // Go through the list of events in order of timestamp. For each case open event, look for the next case closed + // event for that host/user/case name. + for (int caseOpenIndex = 0; caseOpenIndex < dataForReport.size() - 1; caseOpenIndex++) { + if (! dataForReport.get(caseOpenIndex).getEventType().equals(HealthMonitor.UserEvent.CASE_OPEN)) { + continue; + } + + // Try to find the next event logged for this user/host. We do not check that + // it is a case closed event. + HealthMonitor.UserData caseOpenEvent = dataForReport.get(caseOpenIndex); + HealthMonitor.UserData nextEventAfterCaseOpen = null; + for (int nextEventIndex = caseOpenIndex + 1; nextEventIndex < dataForReport.size(); nextEventIndex++) { + HealthMonitor.UserData nextEvent = dataForReport.get(nextEventIndex); + // If the user and host name do not match, ignore this event + if ( nextEvent.getHostname().equals(caseOpenEvent.getHostname()) + && nextEvent.getUserName().equals(caseOpenEvent.getUserName())) { + nextEventAfterCaseOpen = nextEvent; + break; + } + } + + // Prepare the columns + String caseOpenTime = timestampFormat.format(caseOpenEvent.getTimestamp()); + + // If everything is recorded properly then the next event for a given user after + // a case open will be a case close. In this case we record the close time and + // how long the case was open. If the next event was not a case close event + // or if there is no next event (which could happen if Autopsy crashed or if + // there were network issues, or if the user simply still has the case open), + // leave the close time and duration blank. + String caseCloseTime = ""; + String duration = ""; + if (nextEventAfterCaseOpen != null + && nextEventAfterCaseOpen.getEventType().equals(HealthMonitor.UserEvent.CASE_CLOSE) + && nextEventAfterCaseOpen.getCaseName().equals(caseOpenEvent.getCaseName())) { + caseCloseTime = timestampFormat.format(nextEventAfterCaseOpen.getTimestamp()); + duration = getDuration(caseOpenEvent.getTimestamp(), nextEventAfterCaseOpen.getTimestamp()); + } + + String host = caseOpenEvent.getHostname(); + String user = caseOpenEvent.getUserName(); + String caseName = caseOpenEvent.getCaseName(); + + String csvEntry = caseOpenTime + "," + caseCloseTime + "," + duration + "," + host + "," + user + ",\"" + caseName + "\""; + writer.write(csvEntry); + writer.newLine(); + } + } catch (IOException ex) { + throw new HealthMonitorException("Error writing to output file " + reportFile.getAbsolutePath(), ex); + } + } + + /** + * Generate a string representing the time between + * the given timestamps. + * + * @param start The starting timestamp. + * @param end The ending timestamp. + * + * @return The duration as a string. + */ + private String getDuration(long start, long end) { + long durationInSeconds = (end - start) / 1000; + long second = durationInSeconds % 60; + long minute = (durationInSeconds / 60) % 60; + long hours = durationInSeconds / (60 * 60); + + return String.format("%d:%02d:%02d", hours, minute, second); + } + /** * Update the user graphs. * @throws HealthMonitorException From 7736629de14b4ce4b53af07c73ca7625b391656e Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 30 Nov 2020 14:48:49 -0500 Subject: [PATCH 24/42] naming updates, close resources, NPE fix --- ...nCategorizer.java => DomainTokenizer.java} | 37 ++++++++++--------- .../autopsy/coreutils/NetworkUtils.java | 2 +- 2 files changed, 21 insertions(+), 18 deletions(-) rename Core/src/org/sleuthkit/autopsy/coreutils/{DomainCategorizer.java => DomainTokenizer.java} (84%) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/DomainCategorizer.java b/Core/src/org/sleuthkit/autopsy/coreutils/DomainTokenizer.java similarity index 84% rename from Core/src/org/sleuthkit/autopsy/coreutils/DomainCategorizer.java rename to Core/src/org/sleuthkit/autopsy/coreutils/DomainTokenizer.java index 3a51578609..95546762b5 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/DomainCategorizer.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/DomainTokenizer.java @@ -32,7 +32,7 @@ import org.apache.commons.lang3.StringUtils; * Attempts to get the domain from a url/domain provided removing the * subdomain(s). */ -class DomainCategorizer { +class DomainTokenizer { /** * This is a node in the trie. Children in the hashmap are identified by @@ -65,7 +65,7 @@ class DomainCategorizer { private static final String COMMENT_TOKEN = "//"; // singleton instance of this class. - private static DomainCategorizer categorizer = null; + private static DomainTokenizer categorizer = null; /** * Returns the singleton instance of this class. @@ -73,7 +73,7 @@ class DomainCategorizer { * @return The DomainCategorizer instance. * @throws IOException */ - static DomainCategorizer getInstance() throws IOException { + static DomainTokenizer getInstance() throws IOException { if (categorizer == null) { categorizer = load(); } @@ -87,22 +87,25 @@ class DomainCategorizer { * @return The DomainCategorizer instance. * @throws IOException If there is an error reading the file. */ - private static DomainCategorizer load() throws IOException { - InputStream is = DomainCategorizer.class.getResourceAsStream(DOMAIN_LIST); - BufferedReader reader = new BufferedReader(new InputStreamReader(is)); - DomainCategorizer categorizer = new DomainCategorizer(); - while (reader.ready()) { - String line = reader.readLine(); - String trimmed = line.trim(); - if (!StringUtils.isBlank(trimmed) && !trimmed.startsWith(COMMENT_TOKEN)) { - categorizer.addDomainSuffix(trimmed); - } - } + private static DomainTokenizer load() throws IOException { + try (InputStream is = DomainTokenizer.class.getResourceAsStream(DOMAIN_LIST); + InputStreamReader isReader = new InputStreamReader(is); + BufferedReader reader = new BufferedReader(isReader)) { - return categorizer; + DomainTokenizer categorizer = new DomainTokenizer(); + while (reader.ready()) { + String line = reader.readLine(); + String trimmed = line.trim(); + if (!StringUtils.isBlank(trimmed) && !trimmed.startsWith(COMMENT_TOKEN)) { + categorizer.addDomainSuffix(trimmed); + } + } + + return categorizer; + } } - private DomainCategorizer() { + private DomainTokenizer() { } // The top-level trie node. @@ -144,7 +147,7 @@ class DomainCategorizer { */ String getDomain(String domain) { if (StringUtils.isBlank(domain)) { - return null; + return ""; } List tokens = Stream.of(domain.split(DELIMITER)) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/NetworkUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/NetworkUtils.java index 1f22c672ef..31497ab6fd 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/NetworkUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/NetworkUtils.java @@ -75,7 +75,7 @@ public class NetworkUtils { String base = host; try { - base = DomainCategorizer.getInstance().getDomain(host); + base = DomainTokenizer.getInstance().getDomain(host); } catch (IOException ex) { logger.log(Level.WARNING, "Unable to load resources for domain categorization.", ex); } From e707ce43ca8f67838d3a933ff5f6c71a50d03d26 Mon Sep 17 00:00:00 2001 From: apriestman Date: Mon, 30 Nov 2020 17:21:18 -0500 Subject: [PATCH 25/42] Add wait cursor --- .../autopsy/healthmonitor/HealthMonitorDashboard.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorDashboard.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorDashboard.java index 5125f8f005..81fbd99d69 100644 --- a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorDashboard.java +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorDashboard.java @@ -508,11 +508,14 @@ public class HealthMonitorDashboard { File selectedFile = reportFileChooser.getSelectedFile(); UserPreferences.setHealthMonitorReportPath(selectedFile.getParent()); try { + dialog.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); generateCSVUserReport(selectedFile); MessageNotifyUtil.Message.info(Bundle.HealthMonitorDashboard_createUserControlPanel_reportDone(selectedFile.getAbsoluteFile())); } catch (HealthMonitorException ex) { logger.log(Level.SEVERE, "Error generating report", ex); MessageNotifyUtil.Message.error(Bundle.HealthMonitorDashboard_createUserControlPanel_reportError()); + } finally { + dialog.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); } } } From 1e270cc0e3363465137ec745103cdcb7c72a7355 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 1 Dec 2020 08:52:12 -0500 Subject: [PATCH 26/42] fixes for domain rules --- .../autopsy/coreutils/DomainTokenizer.java | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/DomainTokenizer.java b/Core/src/org/sleuthkit/autopsy/coreutils/DomainTokenizer.java index 95546762b5..83210cf661 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/DomainTokenizer.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/DomainTokenizer.java @@ -22,6 +22,7 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.List; import java.util.stream.Collectors; @@ -56,9 +57,13 @@ class DomainTokenizer { private static final String JOINER = "."; // delimiter when used with regex private static final String DELIMITER = "\\" + JOINER; + + private static final String WILDCARD = "*"; + private static final String EXCEPTION_PREFIX = "!"; // taken from https://publicsuffix.org/list/public_suffix_list.dat // file containing line seperated suffixes + // rules for parsing can be found here: https://publicsuffix.org/list/ private static final String DOMAIN_LIST = "public_suffix_list.dat"; // token for comments @@ -89,7 +94,7 @@ class DomainTokenizer { */ private static DomainTokenizer load() throws IOException { try (InputStream is = DomainTokenizer.class.getResourceAsStream(DOMAIN_LIST); - InputStreamReader isReader = new InputStreamReader(is); + InputStreamReader isReader = new InputStreamReader(is, StandardCharsets.UTF_8); BufferedReader reader = new BufferedReader(isReader)) { DomainTokenizer categorizer = new DomainTokenizer(); @@ -122,7 +127,7 @@ class DomainTokenizer { return; } - String[] tokens = domainSuffix.split(DELIMITER); + String[] tokens = domainSuffix.trim().split(DELIMITER); DomainCategory cat = trie; for (int i = tokens.length - 1; i >= 0; i--) { @@ -130,7 +135,7 @@ class DomainTokenizer { if (StringUtils.isBlank(token)) { continue; } - + cat = cat.getOrAddChild(tokens[i]); } } @@ -158,10 +163,26 @@ class DomainTokenizer { DomainCategory cat = trie; for (; idx >= 0; idx--) { - cat = cat.get(tokens.get(idx)); - if (cat == null) { + // an exception rule must be at the beginning of a suffix, and, in + // practice, indicates a domain that would otherwise be a further + // suffix with a wildcard rule per: https://publicsuffix.org/list/ + if (cat.get(EXCEPTION_PREFIX + tokens.get(idx)) != null) { break; } + + DomainCategory newCat = cat.get(tokens.get(idx)); + + // if no matching token can be found, look for wildcard token + if (newCat == null) { + // if no wildcard token can be found, the portion found + // so far is the suffix. + newCat = cat.get(WILDCARD); + if (newCat == null) { + break; + } + } + + cat = newCat; } // if first suffix cannot be found, return the whole domain From a52f21a773d328f0e11a28a9d0bf7958d03422d2 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 1 Dec 2020 12:55:38 -0500 Subject: [PATCH 27/42] do not run tests in os x for travis --- travis_build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/travis_build.sh b/travis_build.sh index d3753fd934..e40bd161f4 100755 --- a/travis_build.sh +++ b/travis_build.sh @@ -17,7 +17,7 @@ echo `df -h .` if [ "${TRAVIS_OS_NAME}" = "osx" ]; then # if os x, just run it - ant -q test-no-regression + # ant -q test-no-regression elif [ "${TRAVIS_OS_NAME}" = "linux" ]; then # if linux use xvfb xvfb-run ant -q test-no-regression From cb1736f33398ae63741d28dcd308c264d462ff11 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 1 Dec 2020 15:44:11 -0500 Subject: [PATCH 28/42] fix for more domains --- .../sleuthkit/autopsy/coreutils/NetworkUtils.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/NetworkUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/NetworkUtils.java index 31497ab6fd..8078a8c6a3 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/NetworkUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/NetworkUtils.java @@ -23,6 +23,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.net.UnknownHostException; import java.util.logging.Level; +import org.apache.commons.lang.StringUtils; public class NetworkUtils { @@ -104,19 +105,21 @@ public class NetworkUtils { if (urlString == null) { return ""; } - String result = ""; + String urlHost = null; try { URL url = new URL(urlString); - result = url.getHost(); + urlHost = url.getHost(); } catch (MalformedURLException ex) { //do not log if not a valid URL - we will try to extract it ourselves } - //was not a valid URL, try a less picky method - if (result == null || result.trim().isEmpty()) { - return getBaseDomain(urlString); - } + // if there is a valid url host, get base domain from that host + // otherwise use urlString and parse the domain + String result = (StringUtils.isNotBlank(urlHost)) + ? getBaseDomain(urlHost) + : getBaseDomain(urlString); + return result; } From bb4f0d0751c4e2dc3a4f5723de8fe6302d71bdfd Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 2 Dec 2020 08:32:57 -0500 Subject: [PATCH 29/42] lower case normalization --- Core/src/org/sleuthkit/autopsy/coreutils/DomainTokenizer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/DomainTokenizer.java b/Core/src/org/sleuthkit/autopsy/coreutils/DomainTokenizer.java index 83210cf661..997931272b 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/DomainTokenizer.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/DomainTokenizer.java @@ -127,7 +127,7 @@ class DomainTokenizer { return; } - String[] tokens = domainSuffix.trim().split(DELIMITER); + String[] tokens = domainSuffix.toLowerCase().trim().split(DELIMITER); DomainCategory cat = trie; for (int i = tokens.length - 1; i >= 0; i--) { @@ -155,7 +155,7 @@ class DomainTokenizer { return ""; } - List tokens = Stream.of(domain.split(DELIMITER)) + List tokens = Stream.of(domain.toLowerCase().split(DELIMITER)) .filter(StringUtils::isNotBlank) .collect(Collectors.toList()); From 7844b79cb68b05ac10e175c3d2ff888978cd61c0 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 2 Dec 2020 08:57:45 -0500 Subject: [PATCH 30/42] travis shell script fix --- travis_build.sh | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/travis_build.sh b/travis_build.sh index e40bd161f4..a561ccd21e 100755 --- a/travis_build.sh +++ b/travis_build.sh @@ -15,10 +15,7 @@ echo "Testing Autopsy..." && echo -en 'travis_fold:start:script.tests\\r' echo "Free Space:" echo `df -h .` -if [ "${TRAVIS_OS_NAME}" = "osx" ]; then - # if os x, just run it - # ant -q test-no-regression -elif [ "${TRAVIS_OS_NAME}" = "linux" ]; then +if [ "${TRAVIS_OS_NAME}" = "linux" ]; then # if linux use xvfb xvfb-run ant -q test-no-regression fi From b8d4f72cda660c2724e99657025a5ecc6f6f5336 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 2 Dec 2020 09:04:39 -0500 Subject: [PATCH 31/42] os x image fix --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index dd6b50f34a..6c06754d37 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ jobs: - os: linux dist: bionic - os: osx + osx_image: xcode12.2 env: global: From 28dead68ad9d54d73d347c0e16fbf1872266ee79 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 2 Dec 2020 10:22:32 -0500 Subject: [PATCH 32/42] update to 12u --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6c06754d37..baeb5dd86a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ jobs: - os: linux dist: bionic - os: osx - osx_image: xcode12.2 + osx_image: xcode12u env: global: From 1d056f34d4e5a88f02895342bbe12784f234e585 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 2 Dec 2020 11:34:51 -0500 Subject: [PATCH 33/42] revert to 12.2 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index baeb5dd86a..6c06754d37 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ jobs: - os: linux dist: bionic - os: osx - osx_image: xcode12u + osx_image: xcode12.2 env: global: From 1a5b0c2b14f110dffe63a0e077c817a310860a80 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Wed, 2 Dec 2020 15:34:55 -0500 Subject: [PATCH 34/42] Sorted context veiwer panels by date time --- .../contextviewer/ContextSourcePanel.java | 18 +++-- .../contextviewer/ContextUsagePanel.java | 17 +++-- .../contextviewer/ContextViewer.java | 71 +++++++++++++++++-- 3 files changed, 92 insertions(+), 14 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextSourcePanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextSourcePanel.java index 284a66cf04..02bd3f2ae6 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextSourcePanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextSourcePanel.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.contentviewers.contextviewer; import java.util.ArrayList; import java.util.List; +import org.sleuthkit.autopsy.contentviewers.contextviewer.ContextViewer.DateTimePanel; import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; import org.sleuthkit.datamodel.BlackboardArtifact; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT; @@ -29,27 +30,36 @@ import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOC * usage, if known. * */ -public final class ContextSourcePanel extends javax.swing.JPanel { +public final class ContextSourcePanel extends javax.swing.JPanel implements DateTimePanel { private static final long serialVersionUID = 1L; // defines a list of artifacts that provide context for a file private static final List SOURCE_CONTEXT_ARTIFACTS = new ArrayList<>(); + static { SOURCE_CONTEXT_ARTIFACTS.add(TSK_ASSOCIATED_OBJECT); } private final BlackboardArtifact sourceContextArtifact; + private final Long dateTime; + /** * Creates new form ContextViewer */ - public ContextSourcePanel(String sourceName, String sourceText, BlackboardArtifact associatedArtifact) { + public ContextSourcePanel(String sourceName, String sourceText, BlackboardArtifact associatedArtifact, Long dateTime) { initComponents(); sourceContextArtifact = associatedArtifact; setSourceName(sourceName); setSourceText(sourceText); + this.dateTime = dateTime; + } + + @Override + public Long getDateTime() { + return dateTime; } /** @@ -140,10 +150,10 @@ public final class ContextSourcePanel extends javax.swing.JPanel { private void showSourceText(boolean show) { jSourceTextLabel.setVisible(show); } - + private void showSourceButton(boolean show) { jSourceGoToResultButton.setVisible(show); - jSourceGoToResultButton.setEnabled(show); + jSourceGoToResultButton.setEnabled(show); } // Variables declaration - do not modify//GEN-BEGIN:variables diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextUsagePanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextUsagePanel.java index de87d7a5e5..4a96dfcffd 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextUsagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextUsagePanel.java @@ -29,27 +29,36 @@ import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOC * usage, if known. * */ -public final class ContextUsagePanel extends javax.swing.JPanel { +public final class ContextUsagePanel extends javax.swing.JPanel implements ContextViewer.DateTimePanel { private static final long serialVersionUID = 1L; // defines a list of artifacts that provide context for a file private static final List SOURCE_CONTEXT_ARTIFACTS = new ArrayList<>(); + static { SOURCE_CONTEXT_ARTIFACTS.add(TSK_ASSOCIATED_OBJECT); } private final BlackboardArtifact sourceContextArtifact; + private final Long dateTime; + /** * Creates new form ContextViewer */ - public ContextUsagePanel(String sourceName, String sourceText, BlackboardArtifact associatedArtifact) { + public ContextUsagePanel(String sourceName, String sourceText, BlackboardArtifact associatedArtifact, Long dateTime) { initComponents(); sourceContextArtifact = associatedArtifact; setUsageName(sourceName); setUsageText(sourceText); + this.dateTime = dateTime; + } + + @Override + public Long getDateTime() { + return dateTime; } /** @@ -138,10 +147,10 @@ public final class ContextUsagePanel extends javax.swing.JPanel { private void showUsageText(boolean show) { jUsageTextLabel.setVisible(show); } - + private void showUsageButton(boolean show) { jUsageGoToResultButton.setVisible(show); - jUsageGoToResultButton.setEnabled(show); + jUsageGoToResultButton.setEnabled(show); } // Variables declaration - do not modify//GEN-BEGIN:variables diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextViewer.java index 77cee389f6..c223f577b0 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextViewer.java @@ -20,6 +20,8 @@ package org.sleuthkit.autopsy.contentviewers.contextviewer; import java.awt.Component; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -56,8 +58,8 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte // defines a list of artifacts that provide context for a file private static final List CONTEXT_ARTIFACTS = new ArrayList<>(); - private final List contextSourcePanels = new ArrayList<>(); - private final List contextUsagePanels = new ArrayList<>(); + private final List contextSourcePanels = new ArrayList<>(); + private final List contextUsagePanels = new ArrayList<>(); static { CONTEXT_ARTIFACTS.add(TSK_ASSOCIATED_OBJECT); @@ -338,32 +340,36 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte "ContextViewer.programExecution=Program Execution: " }) private void addArtifactToPanels(BlackboardArtifact associatedArtifact) throws TskCoreException { + Long dateTime = getArtifactDateTime(associatedArtifact); if (BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() == associatedArtifact.getArtifactTypeID() || BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID() == associatedArtifact.getArtifactTypeID()) { String sourceName = Bundle.ContextViewer_attachmentSource(); String sourceText = msgArtifactToAbbreviatedString(associatedArtifact); - javax.swing.JPanel sourcePanel = new ContextSourcePanel(sourceName, sourceText, associatedArtifact); + ContextSourcePanel sourcePanel = new ContextSourcePanel(sourceName, sourceText, associatedArtifact, dateTime); contextSourcePanels.add(sourcePanel); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID() == associatedArtifact.getArtifactTypeID() || BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CACHE.getTypeID() == associatedArtifact.getArtifactTypeID()) { String sourceName = Bundle.ContextViewer_downloadSource(); String sourceText = webDownloadArtifactToString(associatedArtifact); - javax.swing.JPanel sourcePanel = new ContextSourcePanel(sourceName, sourceText, associatedArtifact); + ContextSourcePanel sourcePanel = new ContextSourcePanel(sourceName, sourceText, associatedArtifact, dateTime); contextSourcePanels.add(sourcePanel); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_RECENT_OBJECT.getTypeID() == associatedArtifact.getArtifactTypeID()) { String sourceName = Bundle.ContextViewer_recentDocs(); String sourceText = recentDocArtifactToString(associatedArtifact); - javax.swing.JPanel usagePanel = new ContextUsagePanel(sourceName, sourceText, associatedArtifact); + ContextUsagePanel usagePanel = new ContextUsagePanel(sourceName, sourceText, associatedArtifact, dateTime); contextUsagePanels.add(usagePanel); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_PROG_RUN.getTypeID() == associatedArtifact.getArtifactTypeID()) { String sourceName = Bundle.ContextViewer_programExecution(); String sourceText = programExecArtifactToString(associatedArtifact); - javax.swing.JPanel usagePanel = new ContextUsagePanel(sourceName, sourceText, associatedArtifact); + ContextUsagePanel usagePanel = new ContextUsagePanel(sourceName, sourceText, associatedArtifact, dateTime); contextUsagePanels.add(usagePanel); } + + Collections.sort(contextSourcePanels, new SortByDateTime()); + Collections.sort(contextUsagePanels, new SortByDateTime()); } /** @@ -532,6 +538,59 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte return attributeMap; } + + interface DateTimePanel { + /** + * Return the date time value for this panel. + * + * @return Date time value or null of one is not available. + */ + Long getDateTime(); + } + + /** + * Return the dateTime value for the given message artifact. + * + * @param artifact + * + * @return Long dateTime value or null if the attribute was not found. + * + * @throws TskCoreException + */ + private Long getArtifactDateTime(BlackboardArtifact artifact) throws TskCoreException { + BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME)); + + if (BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID() == artifact.getArtifactTypeID()) { + attribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT)); + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID() == artifact.getArtifactTypeID() + || BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CACHE.getTypeID() == artifact.getArtifactTypeID()) { + attribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED)); + } + return (attribute != null ? attribute.getValueLong() : null); + } + + /** + * Class for sorting lists of DateTimePanels. + */ + class SortByDateTime implements Comparator { + + @Override + public int compare(DateTimePanel panel1, DateTimePanel panel2) { + Long dateTime1 = panel1.getDateTime(); + Long dateTime2 = panel2.getDateTime(); + + if(dateTime1 == null && dateTime2 == null) { + return 0; + } else if(dateTime1 == null) { + return -1; + } else if(dateTime2 == null) { + return 1; + } + + return dateTime1.compareTo(dateTime2); + } + + } // Variables declaration - do not modify//GEN-BEGIN:variables From c2bcc99fcd32bc1767bb86982d9f5b9dd3c70aec Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 3 Dec 2020 08:18:55 -0500 Subject: [PATCH 35/42] move to private final var instead of function --- .../ui/DataSourceSummaryTabbedPane.java | 31 +++++++------------ 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryTabbedPane.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryTabbedPane.java index 0dde613158..5094e3416e 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryTabbedPane.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryTabbedPane.java @@ -123,7 +123,18 @@ public class DataSourceSummaryTabbedPane extends javax.swing.JPanel { private Runnable notifyParentClose = null; private final IngestJobInfoPanel ingestHistoryPanel = new IngestJobInfoPanel(); - private final List tabs; + private final List tabs = Arrays.asList( + new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_typesTab_title(), new TypesPanel()), + new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_userActivityTab_title(), new UserActivityPanel()), + new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_analysisTab_title(), new AnalysisPanel()), + new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_recentFileTab_title(), new RecentFilesPanel()), + new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_pastCasesTab_title(), new PastCasesPanel()), + new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_timelineTab_title(), new TimelinePanel()), + // do nothing on closing + new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_ingestHistoryTab_title(), ingestHistoryPanel, ingestHistoryPanel::setDataSource, () -> { + }), + new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_detailsTab_title(), new ContainerPanel()) + ); private DataSource dataSource = null; private CardLayout cardLayout; @@ -132,7 +143,6 @@ public class DataSourceSummaryTabbedPane extends javax.swing.JPanel { * Creates new form TabPane */ public DataSourceSummaryTabbedPane() { - this.tabs = getTabs(); initComponents(); postInit(); } @@ -155,23 +165,6 @@ public class DataSourceSummaryTabbedPane extends javax.swing.JPanel { notifyParentClose = parentCloseAction; } - private List getTabs() { - List tabs = Arrays.asList( - new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_typesTab_title(), new TypesPanel()), - new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_userActivityTab_title(), new UserActivityPanel()), - new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_analysisTab_title(), new AnalysisPanel()), - new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_recentFileTab_title(), new RecentFilesPanel()), - new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_pastCasesTab_title(), new PastCasesPanel()), - new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_timelineTab_title(), new TimelinePanel()), - // do nothing on closing - new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_ingestHistoryTab_title(), ingestHistoryPanel, ingestHistoryPanel::setDataSource, () -> { - }), - new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_detailsTab_title(), new ContainerPanel()) - ); - - return tabs; - } - /** * Method called right after initComponents during initialization. */ From aa9900c3385787a44facf3665140a0423afddc14 Mon Sep 17 00:00:00 2001 From: apriestman Date: Thu, 3 Dec 2020 13:57:30 -0500 Subject: [PATCH 36/42] Fix health monitor upgrade --- .../org/sleuthkit/autopsy/healthmonitor/HealthMonitor.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitor.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitor.java index c5c457c81b..f5bddca2d0 100644 --- a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitor.java @@ -157,8 +157,8 @@ public final class HealthMonitor implements PropertyChangeListener { if (!databaseIsInitialized()) { initializeDatabaseSchema(); } - - if (!CURRENT_DB_SCHEMA_VERSION.equals(getVersion())) { + + if (getVersion().compareTo(CURRENT_DB_SCHEMA_VERSION) < 0) { upgradeDatabaseSchema(); } @@ -207,7 +207,7 @@ public final class HealthMonitor implements PropertyChangeListener { if (currentSchema.compareTo(new CaseDbSchemaVersionNumber(1, 2)) < 0) { // Add the user_data table - statement.execute("ALTER TABLE user_data ADD COLUMN username text"); + statement.execute("ALTER TABLE user_data ADD COLUMN IF NOT EXISTS username text"); } // Update the schema version From a2413676f9a6c2f2fe483f1201d5b3e2e0306819 Mon Sep 17 00:00:00 2001 From: apriestman Date: Thu, 3 Dec 2020 14:02:55 -0500 Subject: [PATCH 37/42] Add warning --- .../org/sleuthkit/autopsy/healthmonitor/HealthMonitor.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitor.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitor.java index f5bddca2d0..2a2fc63463 100644 --- a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitor.java @@ -187,6 +187,10 @@ public final class HealthMonitor implements PropertyChangeListener { try (Statement statement = conn.createStatement()) { conn.setAutoCommit(false); + // NOTE: Due to a bug in the upgrade code, earlier versions of Autopsy will erroneously + // run the upgrade if the database is a higher version than it expects. Therefore all + // table changes must account for the possiblility of running multiple times. + // Upgrade from 1.0 to 1.1 // Changes: user_data table added if (currentSchema.compareTo(new CaseDbSchemaVersionNumber(1, 1)) < 0) { From 1b2eae9ec8d1c395a648414c89d856b497046144 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 3 Dec 2020 15:14:15 -0500 Subject: [PATCH 38/42] update menu item text --- .../ui/BaseDataSourceSummaryPanel.java | 10 +++++----- .../datasourcesummary/ui/Bundle.properties-MERGED | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java index 62c804db84..2fe46822a3 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java @@ -64,8 +64,8 @@ import org.sleuthkit.datamodel.TskCoreException; /** * Base class from which other tabs in data source summary derive. */ -@Messages({"UserActivityPanel_goToArtifact=Go to Artifact", - "UserActivityPanel_goToFile=Go to File"}) +@Messages({"BaseDataSourceSummaryPanel_goToArtifact=View Source Result", + "BaseDataSourceSummaryPanel_goToFile=View Source File in Directory"}) abstract class BaseDataSourceSummaryPanel extends JPanel { private static final long serialVersionUID = 1L; @@ -255,7 +255,7 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { } return new CellModelTableCellRenderer.DefaultMenuItem( - Bundle.UserActivityPanel_goToArtifact(), + Bundle.BaseDataSourceSummaryPanel_goToArtifact(), () -> { final DirectoryTreeTopComponent dtc = DirectoryTreeTopComponent.findInstance(); @@ -331,9 +331,9 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { } return new CellModelTableCellRenderer.DefaultMenuItem( - Bundle.UserActivityPanel_goToFile(), + Bundle.BaseDataSourceSummaryPanel_goToFile(), () -> { - new ViewContextAction(Bundle.UserActivityPanel_goToFile(), file) + new ViewContextAction(Bundle.BaseDataSourceSummaryPanel_goToFile(), file) .actionPerformed(null); notifyParentClose(); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED index 5b7a37c275..3f02cd37ed 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED @@ -3,6 +3,8 @@ AnalysisPanel_keyColumn_title=Name AnalysisPanel_keywordSearchModuleName=Keyword Search # {0} - module name BaseDataSourceSummaryPanel_defaultNotIngestMessage=The {0} ingest module has not been run on this data source. +BaseDataSourceSummaryPanel_goToArtifact=View Source Result +BaseDataSourceSummaryPanel_goToFile=View Source File in Directory ContainerPanel_setFieldsForNonImageDataSource_na=N/A CTL_DataSourceSummaryAction=Data Source Summary DataSourceSummaryDialog.closeButton.text=Close @@ -112,8 +114,6 @@ UserActivityPanel.rightClickForMoreOptions3.text=Right click on row for more opt UserActivityPanel.rightClickForMoreOptions4.text=Right click on row for more options UserActivityPanel.rightClickForMoreOptions5.text=Right click on row for more options TimelinePanel.viewInTimelineBtn.text=View in Timeline -UserActivityPanel_goToArtifact=Go to Artifact -UserActivityPanel_goToFile=Go to File UserActivityPanel_noDataExists=No communication data exists UserActivityPanel_tab_title=User Activity UserActivityPanel_TopAccountTableModel_accountType_header=Account Type From deaa670c0e9b4b867a843f89dc3ad71162d3ee66 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Thu, 3 Dec 2020 19:37:06 -0500 Subject: [PATCH 39/42] Improved the icon search algorithm by adding new types --- .../search/DomainSearchThumbnailLoader.java | 69 ++++++++++++++----- 1 file changed, 52 insertions(+), 17 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java index 4a17ad6434..fbcc2e2d55 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java @@ -22,6 +22,7 @@ import com.google.common.cache.CacheLoader; import java.awt.Image; import java.util.List; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -47,8 +48,12 @@ import org.openide.util.ImageUtilities; public class DomainSearchThumbnailLoader extends CacheLoader { private static final String UNSUPPORTED_IMAGE = "org/sleuthkit/autopsy/images/image-extraction-not-supported.png"; - private static final String JPG_EXTENSION = "jpg"; - private static final String JPG_MIME_TYPE = "image/jpeg"; + private static final List SUPPORTED_EXTENSIONS = Arrays.asList("jpg", "svg", "png", "webp", "ico", "gif"); + private static final List SUPPORTED_MIMETYPES = Arrays.asList( + "image/gif", "image/jpeg", "image/png", "image/webp", + "image/svg+xml", "image/vnd.microsoft.icon", "image/x-icon"); + private static final String ICO_EXTENSION = "ico"; + private static final List ICO_MIMETYPES = Arrays.asList("image/vnd.microsoft.icon", "image/x-icon"); private final DomainSearchArtifactsCache artifactsCache; /** @@ -75,8 +80,21 @@ public class DomainSearchThumbnailLoader extends CacheLoader webDownloads = artifactsCache.get(webDownloadsRequest); - final List webDownloadPictures = getJpegsFromWebDownload(caseDb, webDownloads); - Collections.sort(webDownloadPictures, (file1, file2) -> Long.compare(file1.getCrtime(), file2.getCrtime())); + final List webDownloadPictures = getCandidatesFromWebDownloads(caseDb, webDownloads); + Collections.sort(webDownloadPictures, (file1, file2) -> { + // Push ICO to the back of the sorted collection, so that ICO + // is a last resort matching type. + if (isIco(file1) && isIco(file2)) { + return Long.compare(file1.getCrtime(), file2.getCrtime()); + } else if (isIco(file1)) { + return 1; + } else if (isIco(file2)) { + return -1; + } else { + return Long.compare(file1.getCrtime(), file2.getCrtime()); + } + }); + for (int i = webDownloadPictures.size() - 1; i >= 0; i--) { if(Thread.currentThread().isInterrupted()) { throw new InterruptedException(); @@ -92,8 +110,20 @@ public class DomainSearchThumbnailLoader extends CacheLoader webCacheArtifacts = artifactsCache.get(webCacheRequest); - final List webCachePictures = getJpegsFromWebCache(caseDb, webCacheArtifacts); - Collections.sort(webCachePictures, (file1, file2) -> Long.compare(file1.getSize(), file2.getSize())); + final List webCachePictures = getCandidatesFromWebCache(caseDb, webCacheArtifacts); + Collections.sort(webCachePictures, (file1, file2) -> { + // Push ICO to the back of the sorted collection, so that ICO + // is a last resort matching type. + if (isIco(file1) && isIco(file2)) { + return Long.compare(file1.getSize(), file2.getSize()); + } else if (isIco(file1)) { + return 1; + } else if (isIco(file2)) { + return -1; + } else { + return Long.compare(file1.getSize(), file2.getSize()); + } + }); for (int i = webCachePictures.size() - 1; i >= 0; i--) { if(Thread.currentThread().isInterrupted()) { throw new InterruptedException(); @@ -119,16 +149,21 @@ public class DomainSearchThumbnailLoader extends CacheLoader getJpegsFromWebDownload(SleuthkitCase caseDb, List artifacts) throws TskCoreException, InterruptedException { - final List jpegs = new ArrayList<>(); + private List getCandidatesFromWebDownloads(SleuthkitCase caseDb, List artifacts) throws TskCoreException, InterruptedException { + final List candidates = new ArrayList<>(); for (BlackboardArtifact artifact : artifacts) { if(Thread.currentThread().isInterrupted()) { throw new InterruptedException(); } final Content sourceContent = caseDb.getContentById(artifact.getObjectID()); - addIfJpeg(jpegs, sourceContent); + addIfSupported(candidates, sourceContent); } - return jpegs; + return candidates; + } + + private boolean isIco(AbstractFile file) { + return ICO_EXTENSION.equals(file.getNameExtension()) + || ICO_MIMETYPES.contains(file.getMIMEType()); } /** @@ -140,9 +175,9 @@ public class DomainSearchThumbnailLoader extends CacheLoader getJpegsFromWebCache(SleuthkitCase caseDb, List artifacts) throws TskCoreException, InterruptedException { + private List getCandidatesFromWebCache(SleuthkitCase caseDb, List artifacts) throws TskCoreException, InterruptedException { final BlackboardAttribute.Type TSK_PATH_ID = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PATH_ID); - final List jpegs = new ArrayList<>(); + final List candidates = new ArrayList<>(); for (BlackboardArtifact artifact : artifacts) { if(Thread.currentThread().isInterrupted()) { throw new InterruptedException(); @@ -150,10 +185,10 @@ public class DomainSearchThumbnailLoader extends CacheLoader files, Content sourceContent) { + private void addIfSupported(List files, Content sourceContent) { if ((sourceContent instanceof AbstractFile) && !(sourceContent instanceof DataSource)) { final AbstractFile file = (AbstractFile) sourceContent; - if (JPG_EXTENSION.equals(file.getNameExtension()) - || JPG_MIME_TYPE.equals(file.getMIMEType())) { + if (SUPPORTED_EXTENSIONS.contains(file.getNameExtension()) + || SUPPORTED_MIMETYPES.contains(file.getMIMEType())) { files.add(file); } } From e2a337a9cbce8c62903e12d96668234be05175d6 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Thu, 3 Dec 2020 19:40:56 -0500 Subject: [PATCH 40/42] Updated comments --- .../search/DomainSearchThumbnailLoader.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java index fbcc2e2d55..888cc5379b 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java @@ -39,9 +39,10 @@ import org.sleuthkit.datamodel.TskCoreException; import org.openide.util.ImageUtilities; /** - * Loads a thumbnail for the given request. Thumbnail candidates are JPEG files - * that have either TSK_WEB_DOWNLOAD or TSK_WEB_CACHE artifacts that match the - * domain name (see the DomainSearch getArtifacts() API). JPEG files are sorted + * Loads a thumbnail for the given request. Thumbnail candidates types are defined below. + * These candidates types must be the source of either TSK_WEB_DOWNLOAD or + * TSK_WEB_CACHE artifacts that match the + * domain name (see the DomainSearch getArtifacts() API). Candidate files are sorted * by most recent if sourced from TSK_WEB_DOWNLOADs and by size if sourced from * TSK_WEB_CACHE artifacts. The first suitable thumbnail is selected. */ @@ -139,12 +140,12 @@ public class DomainSearchThumbnailLoader extends CacheLoader getCandidatesFromWebCache(SleuthkitCase caseDb, List artifacts) throws TskCoreException, InterruptedException { @@ -192,10 +193,9 @@ public class DomainSearchThumbnailLoader extends CacheLoader files, Content sourceContent) { From 49414ef9a21e07611d0a7697438e495c3d29cd1d Mon Sep 17 00:00:00 2001 From: apriestman Date: Fri, 4 Dec 2020 08:21:05 -0500 Subject: [PATCH 41/42] Change upgrade code since "IF NOT EXISTS" does not work for add column in PG 9.5 --- .../autopsy/healthmonitor/HealthMonitor.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitor.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitor.java index 2a2fc63463..4ad0e23eda 100644 --- a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitor.java @@ -183,6 +183,7 @@ public final class HealthMonitor implements PropertyChangeListener { if (conn == null) { throw new HealthMonitorException("Error getting database connection"); } + ResultSet resultSet = null; try (Statement statement = conn.createStatement()) { conn.setAutoCommit(false); @@ -210,8 +211,13 @@ public final class HealthMonitor implements PropertyChangeListener { // Changes: username added to user_data table if (currentSchema.compareTo(new CaseDbSchemaVersionNumber(1, 2)) < 0) { - // Add the user_data table - statement.execute("ALTER TABLE user_data ADD COLUMN IF NOT EXISTS username text"); + resultSet = statement.executeQuery("SELECT column_name " + + "FROM information_schema.columns " + + "WHERE table_name='user_data' and column_name='username'"); + if (! resultSet.next()) { + // Add the user_data table + statement.execute("ALTER TABLE user_data ADD COLUMN username text"); + } } // Update the schema version @@ -228,6 +234,13 @@ public final class HealthMonitor implements PropertyChangeListener { } throw new HealthMonitorException("Error upgrading database", ex); } finally { + if (resultSet != null) { + try { + resultSet.close(); + } catch (SQLException ex2) { + logger.log(Level.SEVERE, "Error closing result set"); + } + } try { conn.close(); } catch (SQLException ex) { From 2dd08f39b051bc38be39937bf3e01ade11d5db63 Mon Sep 17 00:00:00 2001 From: apriestman Date: Fri, 4 Dec 2020 08:39:07 -0500 Subject: [PATCH 42/42] Make error message more descriptive --- Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitor.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitor.java index 4ad0e23eda..0a8ccfd7aa 100644 --- a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitor.java @@ -984,7 +984,7 @@ public final class HealthMonitor implements PropertyChangeListener { getInstance().writeCurrentStateToDatabase(); } } catch (HealthMonitorException ex) { - logger.log(Level.SEVERE, "Error performing periodic task", ex); //NON-NLS + logger.log(Level.SEVERE, "Error recording health monitor metrics", ex); //NON-NLS } }